Skip to content

useMemo

作用

返回一个 memoized 值。

把“创建”函数和依赖项数组作为参数传入 useMemo,它仅会在某个依赖项改变时才重新计算 memoized 值。这种优化有助于避免在每次渲染时都进行高开销的计算。

栗子

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 result= React.useCallback(() => {
    console.log("result = " + num)
  }, [visible])

  return (
    <div>
      <button onClick={handleClickBtn}>切换Num = {num}</button>
      <button onClick={handleClickChangeVisible}>切换Visible = {visible}</button>
      <button >{result} </button>
    </div>
  )
}

点击切换num ;num得值在不断的增加;但是这时候如果不点击 切换Visible ;result的值永远是 useCallback1。

源码分析

仍然分成两个部分: 初次渲染 和 更新渲染 。此处我们一起讲解

js
/**
 * useMemo 在初次渲染执行方法
 * @param {*} nextCreate
 * @param {*} deps
 * @returns
 */
function mountMemo<T>(
  nextCreate: () => T,
  deps: Array<mixed> | void | null,
): T {
  // 创建 hook
  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 {
  // 找到对应的 hook
  const hook = updateWorkInProgressHook();
  const nextDeps = deps === undefined ? null : deps;
  const prevState = hook.memoizedState;
  if (prevState !== null) {
    // Assume these are defined. If they're not, areHookInputsEqual will warn.
    if (nextDeps !== null) {
      //
      const prevDeps: Array<mixed> | null = prevState[1];
      if (areHookInputsEqual(nextDeps, prevDeps)) {
        return prevState[0];
      }
    }
  }
  // 不能复用 就再次执行
  const nextValue = nextCreate();
  hook.memoizedState = [nextValue, nextDeps];
  return nextValue;
}

其跟useCallback 很像,都将信息以hook的形式保存在 FiberNode.memoizedState上。

image

如何只有deps更新的时候才会生再次执行func生成新的value ?

这就是在updateMemo中实现的,其先获取原来的hook,然后通过areHookInputsEqual(nextDeps, prevDeps)判断新旧hook的deps是够发生更新,如果发生更新就执行nextCreate()返回新的 value ;否则返回旧的prevState[0]。