React Hooks学习笔记:useCreation

182 阅读1分钟

本文是看了掘金小册《玩转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,同时更新函数的计算结果以及修改初始化状态。