React Hook之useCallback和useMemo的使用和源码分析

如何使用

感觉useCallback和useMemo两者很像,前者返回一个memorized的回调函数,后者返回一个memorized的值。

看一下他们是如何定义的

  1. useCallback接受一个回调函数和依赖项数组作为参数,返回回调函数的memorized版本
// useCallback
useCallback<T>(callback: T, deps: Array<mixed> | void | null): T

当这个回调函数传递给自组件时,可以用useCallback避免自组件非必要的渲染


  1. useMemo接受创建函数和依赖项数组作为参数,会在依赖项发生改变时重新计算memorized值
// useMemo
// 创建函数是有返回值的,这是跟useCallback不同的地方
useMemo<T>(nextCreate: () => T, deps: Array<mixed> | void | null): T

要避免每次渲染都进行高开销的计算时可以用useMemo

综上:

  • useCallback(callback, deps) 相当于useMemo(() => fn, deps);
  • deps依赖项数组发生改变时,才会引起useCallbak和useMemo的返回值的更新
  • 不传deps时,组件每次渲染他们都会重新计算;
  • deps传空数组[]时,只有组件首次加载会计算;

源码分析

看源码,两者也是很相似的
还是老套路,首次挂载组件时,走的时mount**, 组件更新时走的是update**
useCallback和useMemo的源码部分比较相似和简单。

// mount阶段就是获取到传入的回调函数和依赖数组,保存到hook的memorizedState中,然后返回回调函数。
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;
}

// update阶段
function updateCallback<T>(callback: T, deps: Array<mixed> | void | null): T {
  const hook = updateWorkInProgressHook();
 // 从hook的memorizedState中获取上次保存的值[callback, deps],
  const nextDeps = deps === undefined ? null : deps;
  const prevState = hook.memoizedState;
  if (prevState !== null) {
    if (nextDeps !== null) {
      const prevDeps: Array<mixed> | null = prevState[1];
      // 比较新的deps和之前的deps是否相等
      if (areHookInputsEqual(nextDeps, prevDeps)) {
      // 如果相等,返回memorized的callback
        return prevState[0];
      }
    }
  }
  // 如果deps发生变化,更新hook的memorizedState,并返回最新的callback
  hook.memoizedState = [callback, nextDeps];
  return callback;
}

useMemo的源码如下:

// mount阶段, 执行创建函数获得返回值
// 保存到hook的memorizedState中[nextValue, nextDeps]
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;
}

// update阶段
function updateMemo<T>(
  nextCreate: () => T,
  deps: Array<mixed> | void | null,
): T {
  const hook = updateWorkInProgressHook();
  // 获取新的deps
  const nextDeps = deps === undefined ? null : deps;
  // 从memorizedState中获得上次保存的值
  const prevState = hook.memoizedState;
  if (prevState !== null) {
    if (nextDeps !== null) {
    // 比较新deps和旧deps是否相等,如果两者相等,返回旧的创建函数的返回值
      const prevDeps: Array<mixed> | null = prevState[1];
      if (areHookInputsEqual(nextDeps, prevDeps)) {
        return prevState[0];
      }
    }
  }
  // 如果deps发生改变,hook中保存新的返回值和deps,并返回新的创建函数的返回值
  const nextValue = nextCreate();
  hook.memoizedState = [nextValue, nextDeps];
  return nextValue;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值