本文是看了掘金小册《玩转React Hooks》后的学习笔记,仅供个人学习使用,想了解小册内容请前往链接支持。
代码
import { useRef } from "react";
import type { DependencyList } from "react";
// 用于对比前后两次 deps 是否相等
const depsAreSame = (
oldDeps: DependencyList,
deps: DependencyList
): boolean => {
if (oldDeps === deps) return true;
for (let i = 0; i < oldDeps.length; i++) {
if (!Object.is(oldDeps[i], deps[i])) return false;
}
return true;
};
const useCreation = <T,>(fn: () => T, deps: DependencyList) => {
// 接收 3 个参数,分别是 deps,函数本身,以及是否进行初始化的判断
const { current } = useRef({
deps,
obj: undefined as undefined | T,
initialized: false,
});
// 如果没进行过初始化 or 前后两次 deps 不相同
// 就直接更新 deps,同时更新函数的计算结果以及修改初始化状态
if (current.initialized === false || !depsAreSame(current.deps, deps)) {
current.deps = deps;
current.obj = fn();
current.initialized = true;
}
return current.obj as T;
};
export default useCreation;
这个 hook 解决了有时候 useCallback 或者 useMemo拿不到最新值的问题,或者 useCallback、useMemo的 deps 更新导致函数更新,从而导致其他副作用,如 useCallback更新导致useEffect 重新执行。因此我们希望有一个函数,函数本身可以被缓存,但是缓存后不会随着 deps 的更新而更新,那么在 hook 中的思路其实很明显了,就是用 ref,因为 useRef 不会触发函数组件的更新,因此我们可以将函数放到 ref.current中。
有了这个前提,我们再来看这个 hook,思路就很清晰了:
如果没进行过初始化 or 前后两次 deps 不相同,就直接更新 deps,同时更新函数的计算结果以及修改初始化状态。