文章主要说明的两点
1、useCallBack不是每个函数都需要使用!
2、useCallBack在什么情况下使用?
useCallBack并不是每一个函数都需要去包裹,虽然它本身是一个缓存工具,但是阻止不了函数每次的重建、
const fun1 = useCallback(() => {
console.log('示例一函数');
}, [])
const fun2 = () => {
console.log('示例二函数');
}
上面有两个函数,一个是使用了useCallBack包裹、一个没有,当我们更新状态导致组件更新的时候,fun2函数会被销毁、重新构建、实际上fun1也会被重新构建,只是被放在了useCallBack内部的管理队列中。
而当我们大量使用useCallBack的时候,管理队列中的函数会非常之多,任何一个使用了useCallBack的组件重新渲染的时候都需要去便利useCallBack内部所有被管理的函数找到需要校验依赖是否改变的函数并进行校验。
useCallBack在什么情况下使用?
在往子组件传入了一个函数并且子组件被React.momo缓存了的时候使用
当父组件当中引用子组件
1、父组件点击更新state,触发渲染,子组件跟着渲染
2、使用memo对子组件进行缓存,点击更新state,子组件不会渲染,memo会对props里面的数据进行比较,不一致的情况才会使子组件更新
3、如果父组件传给子组件的一个函数,我们在更新state时候会导致父组件重新渲染,函数也会被重新构建、返回一个新的函数地址,memo进行比较会返回前后函数的地址不一致, 触发渲染,但是如果传入的是一个带有useCallback的函数,那子组件就不会被重新渲染了,因为两次的函数地址都保持一致
4、useCallBack一般是结合memo来使用,保持最大的优化
import React, { FC, useState, useCallback } from "react";
import Child from "./Child";
const Index: FC = () => {
const fun1 = useCallback(() => {
console.log('示例一函数');
}, [])
const fun2 = () => {
console.log('示例二函数');
}
const [parentState,setParentState] = useState(0); //父组件的state
return (
<div style={{ marginTop: "100px" }}>
{parentState}
<button onClick={() => setParentState(val => val + 1)}>
点击我改变父组件中与Child组件无关的state
</button>
// 传入fun2的时候更新state会触发渲染、因为两次的函数地址不一致
// 使用子组件不传递任何参数,子组件使用memo包裹,当父组件更新state不会触发
<Child fun={fun1} />
</div>
)
}
export default Index
import React, { FC, memo } from "react";
const Child: FC = (props: any) => {
console.log(props,"我被打印了就说明子组件重新构建了")
return (
<div style={{ marginTop: "100px" }}>这是子组件</div>
)
}
const projectName = `hiui-ihaier-child`;
Child.displayName = `HIUI_${projectName.replace(/-/g, "_")}`;
export default memo(Child)