要想学习useMemo必须要先知道React.memo,这两者都有一定的优化作用
memo的作用
当数据变化时,代码会重新执行一遍,但是子组件数据没有变化也会执行,这个时候可以使用memo
将子组件封装起来,让子组件的数据只在发生改变时才会执行
案例
父组件点击countOne+1,子组件的入参countTwo不变,验证程序会不会执行子组件的代码
不使用memo的情况
只改变countOne的值时,虽然说countTwo的值没变,但是也执行了Child的打印语句
const UseMemo = () => {
const [countOne, setOne] = useState(() => 0)
const [countTwo, setTwo] = useState(() => 0)
return (
<div>
<h1>{countOne}</h1>
<button onClick={() => setOne((countOne) => countOne + 1)}>
+countOne
</button>
<button onClick={() => setTwo((countTwo) => countTwo + 1)}>
+countTwo
</button>
<Child count={countTwo}></Child>
</div>
)
}
const Child = (props) => {
console.log('child执行了')
return <div>{props.count}</div>
}
通过运行发现,Child里的代码执行了。
使用memo进行封装
将Child用memo封装一下,就可以使m不变就不执行Child,这个时候只要m的值不变,就不会执行Child组件
使用React.memo封装,会返回一个新的组件,调用新组件
const UseMemo = () => {
const [countOne, setOne] = useState(() => 0)
const [countTwo, setTwo] = useState(() => 0)
return (
<div>
<h1>{countOne}</h1>
<button onClick={() => setOne((countOne) => countOne + 1)}>
+countOne
</button>
<button onClick={() => setTwo((countTwo) => countTwo + 1)}>
+countTwo
</button>
<Child count={countTwo}></Child>
</div>
)
}
const Child = React.memo((props) => {
console.log('child执行了')
return (
<div>
{props.count}
</div>
)
})
这次执行就可以发现,改变了countOne,Child的代码并没有执行。
但是此时还有一个bug,如果在子组件Child上添加一个监听函数,无论修改countTwo的值与否,都会执行Child组件
const UseMemo = () => {
const [countOne, setOne] = useState(() => 0)
const [countTwo, setTwo] = useState(() => 0)
const onClickChild = (props) => {
console.log(props, 'aaaaaaa')
setOne((countOne) => countOne + 1)
}
return (
<div>
<h1>{countOne}</h1>
<button onClick={() => setOne((countOne) => countOne + 1)}>
+countOne
</button>
<button onClick={() => setTwo((countTwo) => countTwo + 1)}>
+countTwo
</button>
{/*但是如果传了一个引用,则React.memo无效。因为引用是不相等的*/}
<Child count={countTwo} onClickChild={onClickChild}></Child>
</div>
)
}
const Child = React.memo((props) => {
console.log('child执行了')
return (
<div
onClick={() => {
console.log('11')
props.onClickChild('我给父组件传值啦!')
}}
>
{props.count}
</div>
)
})
以上代码给Child传了个函数onClickChild,这就导致了即使countTwo没改变,Child也同样会被执行。
这是因为当点击countOne时,就会重新执行父组件代码,onClickChild
空函数的地址会发生改变,所以说此时还是会执行Child的
这个时候就需要useMemo闪亮登场了
useMemo的作用
解决因函数更新而渲染自己的问题,就可以使用useMemo,使用它将函数重新封装
const onClickChild=useMemo(fn,array)
监听变量,第一个参数是函数,第二个参数是依赖,只有依赖变化时才会重新计算函数
第一个参数是 () => value
第二个参数是依赖 [m, n]
const UseMemo = () => {
const [countOne, setOne] = useState(() => 0)
const [countTwo, setTwo] = useState(() => 0)
const onClickChild = useMemo(() => {
console.log('useMemo执行')
return (props) => {
console.log(props, 'aaaaaaa')
setOne((countOne) => countOne + 1)
}
}, [countTwo])
return (
<div>
<h1>{countOne}</h1>
<button onClick={() => setOne((countOne) => countOne + 1)}>
+countOne
</button>
<button onClick={() => setTwo((countTwo) => countTwo + 1)}>
+countTwo
</button>
<Child count={countTwo} onClickChild={onClickChild}></Child>
</div>
)
}
const Child = React.memo((props) => {
console.log('child执行了')
return (
<div
onClick={() => {
console.log('11')
props.onClickChild('我给父组件传值啦!')
}}
>
{props.count}
</div>
)
})
通过以上代码运行改变countOne,Child就不会执行啦
这里要注意下,useMemo是用来消除上面在子组件Child上添加函数,造成子组件重复渲染的问题,
通俗点说就是处理onClickChild这个函数带来的bug
如果Child不是用React.memo包裹的,那么改变countOne同样会触发Child改变。
所以通常二者是结合使用的。
注意:
- 如果你的value是个函数,那么你就要写成
useMemo(() => fn, deps)
- 这是一个返回函数的函数,比较复杂;于是就有了
useCallback
,你可以使用useCallback
useCallback的作用
useCallback(fn, deps) 相当于 useMemo(() => fn, deps)
上面的onClickChild函数用useCallback写法如下:
const UseMemo = () => {
const [countOne, setOne] = useState(() => 0)
const [countTwo, setTwo] = useState(() => 0)
const onClickChild = useCallback(
(props) => {
console.log(props, 'aaaaaaa')
setOne((countOne) => countOne + 1)
},
[countTwo]
)
return (
<div>
<h1>{countOne}</h1>
<button onClick={() => setOne((countOne) => countOne + 1)}>
+countOne
</button>
<button onClick={() => setTwo((countTwo) => countTwo + 1)}>
+countTwo
</button>
{/*但是如果传了一个引用,则React.memo无效。因为引用是不相等的*/}
<Child count={countTwo} onClickChild={onClickChild}></Child>
</div>
)
}
const Child = React.memo((props) => {
console.log('child执行了')
return (
<div
onClick={() => {
console.log('11')
props.onClickChild('我给父组件传值啦!')
}}
>
{props.count}
</div>
)
})
到这里React.memo,useMemo,useCallback就都解释完了,喜欢的小伙伴点个收藏哦。