React 性能优化:cache、memo 和 useMemo 的使用场景对比

111 阅读3分钟

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)

使用建议

  1. 优先使用 memo 优化组件:从顶层开始,逐步向下优化频繁重渲染的组件
  2. useMemo 聚焦计算密集型任务:仅在计算开销明显时使用,避免过度依赖
  3. cache 用于跨组件复用:将通用缓存逻辑抽离为工具函数,避免重复代码