You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

useMemo与React.memo的区别、适用场景及示例问询

关于useMemo与React.memo的区别及适用场景

核心区别

两者都是React性能优化的工具,但作用对象和机制完全不同:

  • React.memo是高阶组件,作用于整个组件,通过对比组件props的变化来决定是否复用之前的渲染结果,避免不必要的组件重渲染。
  • useMemo是React Hook,作用于组件内部的计算值,通过依赖数组控制是否重新执行计算逻辑,缓存复杂计算的结果,避免每次渲染重复消耗算力。

另外,触发缓存更新的条件也不同:

  • React.memo默认做props的浅对比,也可以传入自定义对比函数;只有当props变化时才会重新渲染组件。
  • useMemo仅在依赖数组中的值发生变化时,才会重新执行传入的计算函数,否则直接返回缓存值。

React.memo 适用场景及示例

1. 纯展示型子组件,props极少变化

当子组件只负责展示数据,且接收的props不会随父组件的其他状态变化时,用React.memo包裹可以避免父组件重渲染时子组件跟着无效更新。

// 被React.memo包裹的用户卡片组件
const UserCard = React.memo(({ user }) => {
  console.log('UserCard 触发渲染');
  return (
    <div className="card">
      <h2>{user.nickname}</h2>
      <p>{user.bio}</p>
    </div>
  );
});

// 父组件:自身状态频繁变化,但传给UserCard的props稳定
function ProfilePage() {
  const [tabIndex, setTabIndex] = useState(0);
  // 用useMemo保证user引用稳定,配合React.memo生效
  const userInfo = useMemo(() => ({
    nickname: '前端老鸟',
    bio: '专注React性能优化'
  }), []);

  return (
    <div>
      <div className="tabs">
        <button onClick={() => setTabIndex(0)}>首页</button>
        <button onClick={() => setTabIndex(1)}>动态</button>
      </div>
      {/* 切换tab时,UserCard不会重复渲染 */}
      <UserCard user={userInfo} />
    </div>
  );
}

2. 长列表中的列表项组件

当渲染包含大量项的列表时,个别项数据变化时,React.memo可以保证只有变化的项重新渲染,而非整个列表全量更新。

// 列表项组件
const TodoItem = React.memo(({ todo, onToggle }) => {
  console.log(`渲染待办项:${todo.id}`);
  return (
    <div onClick={() => onToggle(todo.id)}>
      <input type="checkbox" checked={todo.done} />
      <span>{todo.content}</span>
    </div>
  );
});

// 列表父组件
function TodoList({ todos, onToggleTodo }) {
  return (
    <div className="todo-list">
      {todos.map(todo => (
        <TodoItem 
          key={todo.id} 
          todo={todo} 
          onToggle={onToggleTodo} 
        />
      ))}
    </div>
  );
}

当某个待办项的完成状态改变时,只有对应的TodoItem会重新渲染,其他项复用缓存的渲染结果,大幅提升长列表性能。

3. 被频繁重渲染的父组件所包含的子组件

如果父组件因为实时输入、动画等场景频繁重渲染,但子组件的props并不受这些变化影响,用React.memo包裹子组件可以切断无效的渲染传递。


useMemo 适用场景

1. 避免重复执行复杂计算

当组件中存在耗时的计算逻辑(如大数组筛选、排序、统计),且计算结果仅依赖特定变量时,用useMemo缓存计算结果,避免每次渲染都重复消耗资源。

function OrderStatistics({ orders, dateRange }) {
  // 仅当orders或dateRange变化时,重新计算统计数据
  const stats = useMemo(() => {
    console.log('执行订单统计计算');
    return {
      totalAmount: orders.filter(o => o.date >= dateRange.start && o.date <= dateRange.end)
                        .reduce((sum, o) => sum + o.amount, 0),
      completedCount: orders.filter(o => o.status === 'completed').length
    };
  }, [orders, dateRange]);

  return (
    <div className="stats">
      <p>总金额:{stats.totalAmount}</p>
      <p>完成订单数:{stats.completedCount}</p>
    </div>
  );
}

2. 保持引用稳定,配合React.memo生效

当需要将对象、数组或函数作为props传给被React.memo包裹的子组件时,用useMemo缓存这些值,避免每次渲染创建新引用导致子组件误触发重渲染。

function ParentComponent() {
  const [count, setCount] = useState(0);
  // 缓存配置对象,保持引用不变
  const tableConfig = useMemo(() => ({
    columns: ['姓名', '年龄', '职位'],
    pageSize: 10
  }), []);

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>点击次数:{count}</button>
      {/* 点击按钮时,Table不会因为tableConfig引用变化而重渲染 */}
      <DataTable config={tableConfig} />
    </div>
  );
}

3. 缓存自定义Hook的复杂返回值

如果自定义Hook返回的是对象或数组这类引用类型值,用useMemo缓存可以保证返回值的引用稳定,避免使用该Hook的组件因为引用变化而重渲染。

function useChartData() {
  const [timeRange, setTimeRange] = useState('week');
  // 缓存图表数据对象
  const chartData = useMemo(() => {
    // 模拟根据时间范围生成图表数据的复杂逻辑
    return generateChartData(timeRange);
  }, [timeRange]);

  return { chartData, setTimeRange };
}

内容的提问来源于stack exchange,提问作者Akshan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 00:50:07