Skip to content

对应源码:ReactFiberHooks.jsmountMemo / updateMemo / mountCallback / updateCallback

1. useMemo 的实现

javascript
function mountMemo<T>(nextCreate: () => T, deps: Array<mixed> | void | null): T {
  const hook = mountWorkInProgressHook();
  const nextDeps = deps === undefined ? null : deps;
  const nextValue = nextCreate();
  hook.memoizedState = [nextValue, nextDeps];  // 存 [值, 依赖]
  return nextValue;
}

function updateMemo<T>(nextCreate: () => T, deps: Array<mixed> | void | null): T {
  const hook = updateWorkInProgressHook();
  const nextDeps = deps === undefined ? null : deps;
  const prevState = hook.memoizedState;
  // 源码注释:Assume these are defined. If they're not, areHookInputsEqual will warn.
  if (nextDeps !== null) {
    const prevDeps = prevState[1];
    if (areHookInputsEqual(nextDeps, prevDeps)) {
      // 依赖没变 → 返回缓存的值
      return prevState[0];
    }
  }

  // 依赖变了 → 重新计算
  const nextValue = nextCreate();
  hook.memoizedState = [nextValue, nextDeps];
  return nextValue;
}

useMemomemoizedState 不是对象,而是一个 [value, deps] 数组。

2. useCallback 的实现

javascript
function mountCallback<T>(callback: T, deps: Array<mixed> | void | null): T {
  const hook = mountWorkInProgressHook();
  const nextDeps = deps === undefined ? null : deps;
  hook.memoizedState = [callback, nextDeps];  // 存 [回调, 依赖]
  return callback;
}

function updateCallback<T>(callback: T, deps: Array<mixed> | void | null): T {
  const hook = updateWorkInProgressHook();
  const nextDeps = deps === undefined ? null : deps;
  const prevState = hook.memoizedState;
  if (nextDeps !== null) {
    const prevDeps = prevState[1];
    if (areHookInputsEqual(nextDeps, prevDeps)) {
      return prevState[0]; // 返回缓存的函数引用
    }
  }
  hook.memoizedState = [callback, nextDeps];
  return callback;
}

useCallback(fn, deps) 等价于 useMemo(() => fn, deps)。两者唯一的区别是 useMemo 调用工厂函数,useCallback 直接存储函数。React 官方文档 也强调了这一等价关系。

3. React Compiler 的角色

React 19 的 React Compiler 会在编译时自动插入 memoization,让 useMemo/useCallback 变得不必要。I tried React Compiler today 从实践角度评测了 Compiler 的效果:

编译前:                          编译后(Compiler 自动插入):
function Component({ data }) {    function Component({ data }) {
  const value = expensiveCalc();   const $ = useMemoCache(4);  // 4 个槽:2 for value, 2 for onClick
  const onClick = () => {...};     value = $[0] === data ? $[1] : ($[0]=data, $[1]=expensiveCalc());
  return <Child v={value}          const onClick = $[2] === data ? $[3]
    onClick={onClick} />;                 : ($[2]=data, $[3]=()=>{...});
}                                  return <Child v={value} onClick={onClick} />;
                                  }

下一步

参考资料

Released under the MIT License.