React 的 useMemo 是怎么实现的?你自己能造一个吗?

41 次浏览次阅读
没有评论

React useMemo实现原理深度解析:从源码到手动实现

当Vue开发者初次接触React的useMemo时,往往会下意识地将其等同于computed属性。但当我们深入源码时会发现:useMemo本质上是一个带有依赖追踪的计算结果缓存系统,它更像是经过精密设计的备忘录而非响应式魔法。本文将带您穿透表象,解密其核心实现机制,并亲手打造一个简易版useMemo。

一、React useMemo的三大核心实现原理

1.1 Hooks的链表存储结构

React通过单向链表结构存储Hooks状态,每个useMemo对应链表中的一个节点。在组件首次渲染时创建包含三个关键属性的节点:

  • memoizedState:缓存的计算结果
  • dependencies:依赖项数组
  • queue:更新队列(用于调度重计算)

1.2 依赖对比算法

React采用浅比较(shallow compare)进行依赖项比对,其核心逻辑可简化为:

function areDependenciesEqual(prevDeps, nextDeps) {
  for(let i=0; i

1.3 缓存更新策略

当检测到依赖变化时,React会触发同步重计算而非异步更新。源码中的核心逻辑伪代码如下:

function updateMemo(create, deps) {
  const hook = updateWorkInProgressHook();
  const nextDeps = deps === undefined ? null : deps;
  
  if (hook.memoizedState !== null) {
    const prevState = hook.memoizedState;
    if (areDependenciesEqual(prevState.dependencies, nextDeps)) {
      return prevState.memoizedValue;
    }
  }
  
  const nextValue = create();
  hook.memoizedState = { 
    memoizedValue: nextValue,
    dependencies: nextDeps 
  };
  return nextValue;
}

二、手动实现一个简易版useMemo

2.1 存储系统设计

我们使用闭包变量模拟React的Hooks存储机制:

let memoCache = [];
let cursor = 0;

function resetCursor() {
  cursor = 0;
}

2.2 核心逻辑实现

function myUseMemo(create, deps) {
  // 初始化缓存节点
  if (!memoCache[cursor]) {
    memoCache[cursor] = {
      value: create(),
      deps: deps
    };
    cursor++;
    return memoCache[cursor到1].value;
  }

  // 依赖比对
  const shouldRecompute = deps.some((dep, i) => 
    !Object.is(dep, memoCache[cursor].deps[i])
  );

  if (shouldRecompute) {
    memoCache[cursor] = {
      value: create(),
      deps: deps
    };
  }

  cursor++;
  return memoCache[cursor-1].value;
}

2.3 与React实现的关键差异

  • 存储结构差异:使用数组替代链表,简化状态管理
  • 渲染周期处理:缺少React的渲染队列调度机制
  • 依赖处理:未实现React的自动依赖收集功能

三、使用useMemo的五个黄金准则

3.1 必须使用的场景

  • 复杂计算缓存:如矩阵运算、大数据量转换
  • // 计算斐波那契数列
      const fib = useMemo(() => {
        let a=0, b=1;
        for(let i=0; i<100000; i++) [a,b] = [b, a+b];
        return b;
      }, []);
  • 组件渲染优化:避免无效的子组件重渲染
  • const memoizedChild = useMemo(() => , [data]);

3.2 必须警惕的陷阱

  • 过早优化反噬:简单计算使用useMemo反而增加内存开销
  • 依赖数组陷阱:忘记更新依赖项会导致缓存失效
  • 副作用滥用:在useMemo中执行API调用等副作用操作

3.3 性能评估策略

console.time('expensiveCalc');
// 需要缓存的复杂计算
console.timeEnd('expensiveCalc'); // 超过1ms的计算才值得缓存

四、从原理到实践的正确认知

通过源码分析我们发现,useMemo本质上是一个依赖驱动的缓存系统,而非响应式状态管理工具。其实现亮点在于:

  1. 与React渲染流程深度集成的更新机制
  2. 基于Object.is的精确依赖比较算法
  3. 链表结构带来的多Hook协同能力

当我们在日常开发中遇到以下场景时,才是useMemo真正该登场的时候:

  • 计算耗时超过1ms的复杂逻辑
  • 需要保持引用稳定的对象/数组
  • 高频交互组件的渲染优化

记住:性能优化不是银弹,useMemo更不是装饰品。 只有理解其实现原理,才能让这个工具真正为你的应用加速。

正文完
 0

辉哥

一言一句话
-「
最新文章
🚀 CentOS 7 稳定安装 Docker 部署 searxng(国内可用)

🚀 CentOS 7 稳定安装 Docker 部署 searxng(国内可用)

事例:CentOS 7 (Core)。 ⚠️ 关键问题是: 我们走 CentOS 7 专用 + 阿里云镜像稳定...
TikTok直播能赚钱吗?赚到的美金怎么提现?

TikTok直播能赚钱吗?赚到的美金怎么提现?

TikTok直播能赚钱吗?赚到的美金怎么提现详解(2026最新) TikTok作为全球最火的短视频平台,不仅是...
京东618消费券什么时候发?怎么正确使用?

京东618消费券什么时候发?怎么正确使用?

京东618消费券什么时候发?怎么正确使用? 每年京东618都是全年最值得囤货的购物节点,海量消费券直接让到手价...
淘宝网店可以从哪里购买?平台靠谱吗?

淘宝网店可以从哪里购买?平台靠谱吗?

淘宝网店可以从哪里购买?平台靠谱吗? 在电商时代,越来越多的人希望通过淘宝开店实现创业梦想。但从零开始建店需要...
淘宝全球购店铺如何转让?具体操作步骤是什么?

淘宝全球购店铺如何转让?具体操作步骤是什么?

淘宝全球购店铺如何转让?具体操作步骤是什么? 近年来,跨境电商快速发展,淘宝全球购作为阿里巴巴旗下重要的跨境平...
出售淘宝三钻店铺要什么条件?流程复杂吗?

出售淘宝三钻店铺要什么条件?流程复杂吗?

出售淘宝三钻店铺要什么条件?流程复杂吗? 在电商创业热潮中,很多新手卖家都希望快速起步,避免从零开始漫长的信誉...
2026年淘宝双皇冠店铺怎么转让?两个皇冠靠谱吗?

2026年淘宝双皇冠店铺怎么转让?两个皇冠靠谱吗?

2026年淘宝双皇冠店铺怎么转让?两个皇冠靠谱吗? 2026年,淘宝平台竞争更加激烈,很多新手创业者选择直接接...
淘宝闪购入口在哪里?免单玩法怎么操作?

淘宝闪购入口在哪里?免单玩法怎么操作?

淘宝闪购入口在哪里?免单玩法怎么操作? 淘宝闪购是淘宝App上的一级核心频道,主打限时优惠、品牌好物和快速送达...
2026年1688店铺怎么转让?开一家1688要多少钱?

2026年1688店铺怎么转让?开一家1688要多少钱?

2026年1688店铺怎么转让?开一家1688要多少钱? 在2026年,1688作为阿里巴巴旗下的B2B批发平...
淘宝闪购免单卡和请客卡怎么获得?

淘宝闪购免单卡和请客卡怎么获得?

淘宝闪购免单卡和请客卡怎么获得? 在淘宝购物时,最让人兴奋的莫过于各种省钱福利,尤其是闪购频道的免单卡和请客卡...
2026年淘宝开店必须实名认证吗?在哪里查看认证?

2026年淘宝开店必须实名认证吗?在哪里查看认证?

2026年淘宝开店必须实名认证吗?在哪里查看认证? 2026年想在淘宝开店的卖家越来越多,但很多人对实名认证规...