最近在学习react的性能优化,看到了很多useCallback的文章,以下是我的理解。
看源码可以知道,useCallback包过的函数,不管依赖值更没更新,都会重新创建这个函数,但创建函数的性能消耗是很小的,然后useCallback为了去对比依赖值,会把上次的函数也存下来,再去对比这两次的依赖值,所以不要滥用useCallback,这些存储都是会影响性能的
function updateCallback<T>(
callback: T, // useCallback 的第一个参数
deps: Array<mixed> | void | null // useCallback 的第二个参数
): T {
// 取到当前的 useCallback 语句对应的 hook 节点,
const hook = updateWorkInProgressHook();
// 当前的依赖,后面拿来和上一次的依赖进行比较
const nextDeps = deps === undefined ? null : deps;
// 取到上一次缓存的函数
const prevState = hook.memoizedState;
if (prevState !== null) {
// 传了 useCallbck 的第二个参数才走到这里
if (nextDeps !== null) {
const prevDeps: Array<mixed> | null = prevState[1];
// 上一次的依赖和这一次的依赖进行比较,
// 相同就直接返回缓存的结果
if (areHookInputsEqual(nextDeps, prevDeps)) {
return prevState[0];
}
}
}
hook.memoizedState = [callback, nextDeps];
return callback;
}
最合适的场景就是再给子组件传函数的时候,并且这个子组件是有写React.memo或者shouldComponentsUpdate时,才会去比较porps的参数来决定要不要重新渲染整个子组件,而且我们都知道就算函数内容没变化,相比之下也是false,这时用useCallback包住,让他返回上次的函数,子组件就不会重新渲染了。
() => {} === () => {} // false