memo和useMemo
memo在props不变情况下跳过重新渲染,可以达到一些性能优化。
1. 使用memo
如果我们有多个组件,改变其中一个也会让其他组件一起渲染:
jsx
import { useState } from 'react'
function Head() {
return (
<div>
Head 组件
{Math.random()}
</div>
)
}
function App() {
const [num, setNum] = useState(0)
const clickHandle = ()=>{
setNum(num+1)
}
return (
<div>
<button onClick={clickHandle}>点击</button>
{num}
<Head />
</div>
)
}
export default App
运行效果: 使用memo后:
jsx
import { useState, memo } from 'react'
// 使用memo,将之前的head组件包起来
const Head = memo(function Head() {
return (
<div>
Head 组件
{Math.random()}
</div>
)
})
function App() {
const [num, setNum] = useState(0)
const clickHandle = ()=>{
setNum(num+1)
console.log(num)
}
return (
<div>
<button onClick={clickHandle}>点击</button>
{num}
<Head />
</div>
)
}
export default App
运行可以看到Head组件跳过了渲染: 但如果进行了传值,传的值有变化就还是会渲染:
jsx
import { useState, memo } from 'react'
const Head = memo(function Head() {
return (
<div>
Head 组件
{Math.random()}
</div>
)
})
function App() {
const [num, setNum] = useState(0)
const clickHandle = ()=>{
// setNum(1) Head组件只会渲染1次
// 每次num都会发生改变,每次还是会渲染Head组件
setNum(num+1)
console.log(num)
}
return (
<div>
<button onClick={clickHandle}>点击</button>
{num}
<Head items={num}/>
</div>
)
}
export default App
如果传值不是简单值而是对象或者数组,即使传值没有改变也会触发Head组件渲染,因为底层是通过Object.is()
进行比较新旧值,内存地址变了也算。
2. 使用useMemo缓存数据
使用useMemo可以缓存对象或者数组的值,避免实际没有改变的传值而被渲染组件:
jsx
import { useState, memo, useMemo } from 'react'
const Head = memo(function Head() {
return (
<div>
Head 组件
{Math.random()}
</div>
)
})
function App() {
const [num, setNum] = useState(0)
const [msg, setMsg] = useState('hello')
// Head组件中传入msgArr, 虽然点击按钮修改的是num值,但是也会渲染Head
const msgArr = [msg.toUpperCase(), msg.toLowerCase()]
// 将数组数据缓存起来,不同的作用域都可以使用相同的对象,Head组件不会渲染
// 第二个参数表示依赖项,比如指定msg改了后缓存更新
const list = useMemo(()=> [msg.toUpperCase(), msg.toLowerCase()], [msg])
const clickHandle = ()=>{
setNum(num+1)
console.log(num)
}
return (
<div>
<button onClick={clickHandle}>点击</button>
{num}
<Head items={list}/>
</div>
)
}
export default App
运行效果: