cache、memo 和 useMemo对比表格
| 维度 | cache(缓存) | memo(React.memo) | useMemo(Hook) |
|---|---|---|---|
| 所属类型 | 通用编程概念(非 React 专属) | React 高阶组件(HOC) | React 自定义 Hook |
| 作用范围 | 函数级、全局级缓存 | 组件级缓存(包裹函数组件) | 函数级缓存(在组件内使用) |
| 依赖管理 | 手动管理缓存键值对 | 自动浅比较 props(可自定义比较函数) | 显式声明依赖数组(deps) |
| 主要用途 | 避免重复执行纯函数计算(如数学运算、API 请求) | 避免组件因 props 变化无必要重渲染 | 缓存计算结果(如复杂数据处理、回调函数) |
| 示例代码 | js<br>const cachedFn = cache((a, b) => a + b);<br>cachedFn(1, 2); // 直接返回3<br> | js<br>const MemoComponent = memo(MyComponent);<br>// 当props不变时不重新渲染<br> | js<br>const result = useMemo(() => {<br> return expensiveCalculation();<br>}, [deps]);<br> |
| 性能影响 | 需手动维护缓存状态,可能产生内存泄漏 | 浅比较开销小,但复杂对象可能误判 | 依赖数组不更新会导致缓存失效或过时 |
| 典型场景 | - 复杂数学公式计算 - 频繁调用的纯函数 | - 列表项组件(如 TodoItem) - 接收静态 props 的子组件 | - 生成图表数据 - 过滤 / 排序大型数组 - 创建回调函数 |
| 注意事项 | - 需处理缓存失效(如版本控制) - 避免缓存异步操作 | - 无法缓存组件内部状态变化 - 需配合useCallback使用 | - 依赖数组必须正确声明 - 避免过度使用导致逻辑混乱 |
深度解析:三种缓存机制的应用场景
1. cache(通用缓存)
-
核心原理:通过 Map 或对象存储函数参数与结果的映射关系,相同参数直接返回缓存值
-
适用场景:
- 纯函数计算(如计算斐波那契数列、数学公式转换)
- 频繁调用但输入参数变化少的函数
- 前端复杂数据处理(如日期格式化、字符串转换)
-
实现方式:
javascript
// 手动实现缓存函数 function cache(fn) { const cacheMap = new Map(); return function(...args) { const key = args.toString(); if (cacheMap.has(key)) { return cacheMap.get(key); } const result = fn.apply(this, args); cacheMap.set(key, result); return result; }; }
2. memo(React.memo)
-
核心原理:通过浅比较组件 props,若未变化则直接复用上次渲染结果
-
典型案例:
javascript
// 未优化的列表组件 function ListItem({ item }) { console.log('渲染ListItem'); return <div>{item.text}</div>; } // 优化后(使用memo) const OptimizedListItem = memo(ListItem); // 父组件中使用 function List({ items }) { return ( <ul> {items.map(item => ( <OptimizedListItem key={item.id} item={item} /> ))} </ul> ); } -
进阶优化:通过
React.memo的第二个参数自定义比较逻辑javascript
const MemoComponent = memo( MyComponent, (prevProps, nextProps) => prevProps.id === nextProps.id );
3. useMemo(Hook 缓存)
-
核心价值:避免在组件每次重渲染时重复执行高开销操作
-
典型场景:
javascript
function DataTable({ data, filters }) { // 错误做法:每次渲染都重新计算 const filteredData = data.filter(item => { // 复杂过滤逻辑 return item.value > filters.threshold; }); // 正确做法:使用useMemo缓存计算结果 const filteredData = useMemo(() => { return data.filter(item => item.value > filters.threshold); }, [data, filters.threshold]); // ...渲染表格 } -
与 useCallback 的区别:
useMemo返回缓存值(如数组、对象)useCallback返回缓存函数(等价于useMemo(() => fn, deps))
使用建议
- 优先使用 memo 优化组件:从顶层开始,逐步向下优化频繁重渲染的组件
- useMemo 聚焦计算密集型任务:仅在计算开销明显时使用,避免过度依赖
- cache 用于跨组件复用:将通用缓存逻辑抽离为工具函数,避免重复代码