React 的 useMemo 是怎么实现的?你自己能造一个吗?
- 工作日记
- 2025-08-25
- 59热度
- 0评论
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本质上是一个依赖驱动的缓存系统,而非响应式状态管理工具。其实现亮点在于:
- 与React渲染流程深度集成的更新机制
- 基于Object.is的精确依赖比较算法
- 链表结构带来的多Hook协同能力
当我们在日常开发中遇到以下场景时,才是useMemo真正该登场的时候:
- 计算耗时超过1ms的复杂逻辑
- 需要保持引用稳定的对象/数组
- 高频交互组件的渲染优化
记住:性能优化不是银弹,useMemo更不是装饰品。 只有理解其实现原理,才能让这个工具真正为你的应用加速。
