useMemo模拟useCallback

2023-10-26

useMemo缓存结果,useCallback缓存函数

1、看一下useMemo和useCallback底层源码的区别

useMemo 源码实现

组件首次渲染时 useMemo 的源码实现:

// React 版本:16.13.1
// react-reconciler/src/ReactFiberHooks.new.js
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; // 返回缓存后的变量值
}

useMemo 的依赖项发生变化时useMemo的源码实现:

// React 版本:16.13.1
// react-reconciler/src/ReactFiberHooks.new.js
function updateMemo<T>(
  nextCreate: () => T,
  deps: Array<mixed> | void | null,
): T {
  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;
}

依赖对比:

function areHookInputsEqual(nextDeps, prevDeps) {
  if (prevDeps === null) {
    {
      warning$1(false, '%s received a final argument during this render, but not during ' + 'the previous render. Even though the final argument is optional, ' + 'its type cannot change between renders.', currentHookNameInDev);
    }
    return false;
  }

  {
    // Don't bother comparing lengths in prod because these arrays should be
    // passed inline.
    if (nextDeps.length !== prevDeps.length) {
      warning$1(false, 'The final argument passed to %s changed size between renders. The ' + 'order and size of this array must remain constant.\n\n' + 'Previous: %s\n' + 'Incoming: %s', currentHookNameInDev, '[' + nextDeps.join(', ') + ']', '[' + prevDeps.join(', ') + ']');
    }
  }
  for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++) {
    if (is(nextDeps[i], prevDeps[i])) {
      continue;
    }
    return false;
  }
  return true;
}


/**
 * inlined Object.is polyfill to avoid requiring consumers ship their own
 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
 */
function is(x, y) {
  return x === y && (x !== 0 || 1 / x === 1 / y) || x !== x && y !== y // eslint-disable-line no-self-compare
  ;
}

注意:上面react包括state和props对比都是采用shallowEaque,只比较一层。且依赖是对象时X===Y不同对象即使内容一样仍然return false,如下案例,除非前两种useMemo才不会更新,否则每次都更新,useEffect及useCallback同理,useMemo常用来缓存组件,所以不要乱用useMemo等hooks

const [obj, setObj] = useState({a:1})



//如点击等导致state更新
setObj(obj)
setObj(preObj=>preObj)
setObj(preObj=>{...preObj})

useMemo(()=>{....},[obj]

useCallback 源码实现

组件首次渲染时 useCallback 的源码实现:

// React 版本:16.13.1
// react-reconciler/src/ReactFiberHooks.new.js
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;
}

useCallback 的依赖项发生变化时useMemo的源码实现:

// React 版本:16.13.1
// react-reconciler/src/ReactFiberHooks.new.js
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 (prevState !== null) {
    if (nextDeps !== null) {
      const prevDeps: Array<mixed> | null = prevState[1];
      if (areHookInputsEqual(nextDeps, prevDeps)) {
        return prevState[0];
      }
    }
  }
  hook.memoizedState = [callback, nextDeps];
  return callback;
}

useMemo 和 useCallback 都是返回一个缓存后的值,useMemo 返回的是一个缓存后的变量,而useCallback 返回的是一个缓存后的回调函数。可以在 useMemo 的 "创建函数" 中返回一个回调函数来模拟 useCallback 的功能。useMemo 和 useCallback 可以用来解决函数组件更新过程中的性能问题。

// 使用 useCallback 缓存函数
  const addClick = useCallback(() => {
    let sum = 0;
    for (let i = 0; i < count; i++) {
      sum += i;
    }
    return sum;
  }, [count]);



// 使用 useMemo替代useCallback 缓存函数
  const addClick = useMemo(() => () => {
    let sum = 0;
    for (let i = 0; i < count; i++) {
      sum += i;
    }
    return sum;
  }, [count]);

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

useMemo模拟useCallback 的相关文章

随机推荐

  • html中使行级标签隐藏显示出来,HTML标签显示类型

    HTML标签显示类型 HTML5学堂 码匠 依据HTML标签默认显示效果的不同 可以将HTML5标签简单的分为三大类 需要注意 在实际的分类中 并不仅仅是三类 一类是块状元素 一类是行元素 其他的元素显示类型较多 可以统一归为一类 在各类标
  • “面试造飞机,上岗拧螺丝“?2023软件测试岗面试真题超全面整理(最新版)

    软件测试这个岗位 想要找到一份高薪的工作 离不开繁杂的面试程序 这相信是很多准备应聘软件测试岗的朋友难题 很多已经在职多年的软件测试工程师对于这个岗位面试都谈虎色变 那么 为什么软件测试岗位的面试这么难呢 第一 软件测试属于互联网IT行业
  • 禁止本地中断

    禁止本地CPU中断是确保一组内核语句被当作一个临界区处理的主要机制 这个机制的意义是 即使当硬件设备产生了一个IRQ信号时 中断禁止也让内核控制路径继续执行 因此 这就提供了一种有效的方式 确保内核控制路径中的一些中断处理程序能访问的数据结
  • mes系统和plc通讯案例_MES系统与PLC数据集成主要方式

    现在工业化在迅速的发展 当然在发展过程中是离不开系统和软件的辅助 其中MES系统 ERP软件 PLC数据集成对企业有重要作用 那么MES系统与PLC数据集成主要方式有哪些 方式1 定期抓取数据 因为现在生产设备参数都是模拟量 数值一直在不停
  • CGI详解(原理,配置及访问)

    一 基本原理 CGI 通用网关接口 Common Gateway Interface 是一个Web服务器主机提供信息服务的标准接口 通过CGI接口 Web服务器就能够获取客户端提交的信息 转交给服务器端的CGI程序进行处理 最后返回结果给客
  • Java构造多边形的各点坐标合理性判断并抛出异常

    好久没有发过文章了 今天心情好 分享以下今天的java作业吧 题目要求是 构造多边形 并在点无法构造多边形时抛出对应的异常原因 直接上代码 1 构造点坐标 public class Point public int x y public P
  • React Native入门系列:创建我的第一个RN Project

    一 前言 1 准备 在创建RN之前 我们需要先安装相应的工具和搭建环境 可以参考我上一篇文章 React Native入门系列 如何搭建RN环境 Windows篇 2 目标 本章例子中文章达到目标 创建RN项目步骤 在创建中遇见的问题解决
  • Java学习之MyBatis

    1 与其他的ORM框架不同 MyBatis并没有将Java对象与数据库表关联起来 而是将Java方法与SQL语句关联 MyBatis提供了默认情况下基于Java HashMap的缓存实现 每个MyBatis应用程序主要都是使用SqlSess
  • ModuleNotFoundError: No module named ‘distutils.util‘ 解决在colab切换python3.7遇到的报错

    参考 colab修改python版本 mh 的博客 CSDN博客 colab python版本 已解决 ModuleNotFoundError No module named distutils util Harajukuuuu的博客 CS
  • 等保2.0 安全计算环境-服务器-Linux(三级系统)

    目录 1 身份鉴别 A 应对登录用户进行身份标识和鉴别 身份标识具有唯一性 身份鉴别信息具有复杂度要求并定期更换 1 询问管理员 了解系统是否已设置密码 核查登录过程中系统账户是否使用密码进行验证登录 2 查看是否存在空口令账户 3 检查密
  • Java开发常用指令

    Java开发常用指令 一 在IDEA terminal中常用命令 1 清理maven项目target内容 2 编译 打包一体化执行 3 编译 打包免test单元测试执行 二 纯JDK操作命令 1 编译java文件Hello java 2 运
  • 如何在vscode 背景配置一个动态小女孩

    D Microsoft VS Code resources app out vs code electron browser workbench
  • Do not access Object.prototype method ‘hasOwnProperty‘ from target object.问题的解决

    今天用vue写demo的时候想用hasOwnProperty这个api 去判断对象是否包含该值 出现了以上错误 这是我的写法 放在if里做条件判断 解决办法 改为这样的写法 即todo hasOwnProperty isEdit gt Ob
  • 计算机英语(编程词汇大全)

    计算机英语 编程词汇大全 来源地址 https blog csdn net D hj05 article details 80274471 application pl ke n 应用程式 应用 应用程序 application frame
  • OLED透明屏技术:引领品牌营销的视觉革命

    在当今竞争激烈的市场中 品牌营销的成功与否关系到企业的生存和发展 而随着科技的不断进步 新的广告展示技术不断涌现 其中OLED透明屏技术以其独特的视觉效果和创新性的应用在品牌营销领域引起了广泛关注 那么 尼伽将详细介绍OLED透明屏技术以及
  • ROS学习第三天 ROS的通讯机制

    感谢3 1 常用API Autolabor ROS机器人入门课程 ROS理论与实践 零基础教程 第三节 ROS的通讯机制 这一节主要讲的是通讯机制 就像前面说的那样 ROS通过节点发布信息 节点订阅信息实现通讯 基本的通讯机制主要有三种 话
  • vue-router中的#

    vue工程搭建完成后 我们运行在浏览器中打开 会发现url中多了一个 符号 有 是使用URL hash模式的缘故 代表网页中的一个位置 右边的字符就是该位置的标识符 从 开始的部分就是URL的锚部分 vue router默认的是hash模式
  • 具备“记忆”功能的VBA目录选择器

    大家使用任意一款浏览器 例如 Chrome Edge 下载文件时 如果 另存为 对话框选择C Download 那么下次再次使用 另存为 功能 对话框默认显示C Download 而不是根目录 在VBA开发中调用目录选择器并不复杂 但是这个
  • JDBCUtils工具类及其使用

    JDBCUtils工具类及其使用 1 作用 用于连接数据库 关闭资源 减少每次的关闭连接 避免代码冗余 2 JDBCUtils的创建 定义相关属性 4个 因为只需要一份所以用static关键字 定义相关属性 4个 因为只需要一份所以用sta
  • useMemo模拟useCallback

    useMemo缓存结果 useCallback缓存函数 1 看一下useMemo和useCallback底层源码的区别 useMemo 源码实现 组件首次渲染时 useMemo 的源码实现 React 版本 16 13 1 react re