标准答案
- 先用 React DevTools Profiler 或日志确认哪些组件在重渲染,以及重渲染是否真的有性能问题。
- 把状态放到真正需要它的最近公共父组件,避免父组件大状态变化牵连整棵子树。
- 拆分组件,让频繁变化的状态只影响小范围组件。
- 给重组件使用 React.memo,并配合稳定的对象、数组和函数引用。
- 拆分 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 中,任何小变化都影响大量组件。