标准答案

  1. 先用 React DevTools Profiler 或日志确认哪些组件在重渲染,以及重渲染是否真的有性能问题。
  2. 把状态放到真正需要它的最近公共父组件,避免父组件大状态变化牵连整棵子树。
  3. 拆分组件,让频繁变化的状态只影响小范围组件。
  4. 给重组件使用 React.memo,并配合稳定的对象、数组和函数引用。
  5. 拆分 context,避免一个大 context 变化导致所有消费者重渲染;长列表还要考虑虚拟滚动。

题目解析

这道题最重要的是先测量。不是每次重渲染都是问题,React 正常重渲染通常很便宜。

很多无意义重渲染来自状态放得太高、props 引用每次变化、context 粒度过粗。

优化要避免为了少渲染牺牲可读性。只有重组件、长列表、高频交互才值得投入更多优化。

代码示例

下面通过 memo 和稳定回调减少列表行的无意义重渲染。

TSX
const UserRow = memo(function UserRow({
  user,
  onSelect
}: {
  user: User
  onSelect: (id: string) => void
}) {
  return <button onClick={() => onSelect(user.id)}>{user.name}</button>
})

function UserList({ users }: { users: User[] }) {
  const handleSelect = useCallback((id: string) => {
    selectUser(id)
  }, [])

  return users.map(user => (
    <UserRow key={user.id} user={user} onSelect={handleSelect} />
  ))
}

常见误区

  • 看到组件重渲染就立刻加 memo,没有确认是否有真实性能问题。
  • memo 子组件但每次传入新对象、新数组、新函数,导致缓存基本失效。
  • 把所有状态放在页面顶层或大 context 中,任何小变化都影响大量组件。

作者信息