Appearance
useCallback
作用
返回一个 memoized 回调函数。
把内联回调函数及依赖项数组作为参数传入 useCallback,它将返回该回调函数的 memoized 版本,该回调函数仅在某个依赖项改变时才会更新。当你把回调函数传递给经过优化的并使用引用相等性去避免非必要渲染(例如 shouldComponentUpdate)的子组件时,它将非常有用。
useCallback(fn, deps) 相当于 useMemo(() => fn, deps)。
栗子
js
const App = (props) => {
// 添加一个 hook
const [num, setNum] = React.useState(1);
const [visible, setVisible] = React.useState(true);
const handleClickBtn = () => {
setNum((num2) => num2 + 2);
};
// 切换visible
const handleClickChangeVisible = () => {
setNum(!visible);
};
// 打印
const doSome = React.useCallback(() => {
console.log("useCallback" + num);
}, [visible]);
return (
<div>
<button onClick={handleClickBtn}>切换Num = {num}</button>
<button onClick={handleClickChangeVisible}>
切换Visible = {visible}
</button>
<button onClick={doSome}>查看doSome打印的内容 </button>
</div>
);
};点击切换 num ;num 得值在不断的增加;但是这时候如果不点击 切换 Visible ;点击 doSome 的值永远是 useCallback1。
源码分析
仍然分成两个部分: 初次渲染 和 更新渲染 。此处我们一起讲解
js
/**
* useCallback 在初次渲染执行方法
* @param {*} callback
* @param {*} deps
* @returns
*/
function mountCallback<T>(callback: T, deps: Array<mixed> | void | null): T {
// 创建 hook
const hook = mountWorkInProgressHook();
// 创建 deps
const nextDeps = deps === undefined ? null : deps;
// 生成 memoizedState
hook.memoizedState = [callback, nextDeps];
return callback;
}
/**
* useCallback 在更新渲染执行方法
* @param {*} callback
* @param {*} deps
* @returns
*/
function updateCallback<T>(callback: T, deps: Array<mixed> | void | null): T {
// 找到对应的 hook
const hook = updateWorkInProgressHook();
const nextDeps = deps === undefined ? null : deps;
// 找到旧的memoizedState
const prevState = hook.memoizedState;
if (prevState !== null) {
if (nextDeps !== null) {
const prevDeps: Array<mixed> | null = prevState[1];
// 比较新旧deps是否相等
// 如果不等就 返回新的callback
if (areHookInputsEqual(nextDeps, prevDeps)) {
return prevState[0];
}
}
}
hook.memoizedState = [callback, nextDeps];
return callback;
}其跟 useState、useEffect 很像,都将信息以 hook 的形式保存在 FiberNode.memoizedState 上。
如何只有 deps 更新的时候才会生成新的 callback?
这就是在 updateCallback 中实现的,其先获取原来的 hook,然后通过areHookInputsEqual(nextDeps, prevDeps)判断新旧 hook 的 deps 是够发生更新,如果发生更新就返回新的 callback;否则返回旧的 prevState[0]。
