zoukankan      html  css  js  c++  java
  • useCallback和useMemo源码分析

    欢迎关注前端早茶,与广东靓仔携手共同进阶

    前端早茶专注前端,一起结伴同行,紧跟业界发展步伐~

    公众号作者:广东靓仔

    使用

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

    看一下他们是如何定义的

    useCallback接受一个回调函数和依赖项数组作为参数,返回回调函数的memorized版本

    // useCallback
    useCallback<T>(callback: T, deps: Array<mixed> | void | null): T


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

    useMemo接受创建函数和依赖项数组作为参数,会在依赖项发生改变时重新计算memorized值
    // useMemo
    // 创建函数是有返回值的,这是跟useCallback不同的地方

    useMemo<T>(nextCreate: () => T, deps: Array<mixed> | void | null): T


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

    小结

    1、useCallback(callback, deps) 相当于useMemo(() => fn, deps);
    2、deps依赖项数组发生改变时,才会引起useCallbak和useMemo的返回值的更新
    3、不传deps时,组件每次渲染他们都会重新计算;
    4、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;
    }

    两者从源码看,还是很相似的

    欢迎关注前端早茶,与广东靓仔携手共同进阶

    前端早茶专注前端,一起结伴同行,紧跟业界发展步伐~

    公众号作者:广东靓仔

  • 相关阅读:
    Java面向对象之封装静态
    分布式平台Spark环境的搭建
    高斯混合模型
    异常排除: 调用方未由服务进行身份验证
    HttpClient介绍和简单使用流程
    阿里短信服务的使用流程
    笔记工具选择
    特效图文制作
    语言基础(23):智能指针
    无线通信基础(一):无线网络演进
  • 原文地址:https://www.cnblogs.com/cczlovexw/p/15176084.html
Copyright © 2011-2022 走看看