State 的改变会触发重新渲染,而结构不良的 state 可能会导致远超必要的重新渲染——使应用程序变慢。关键策略:窄化订阅、拆分 state、memoize 以及保持 state 的局部性。
1. 仅订阅您需要的最小 slice
jsx
// ❌ subscribing to the whole store → re-renders on ANY change
const store = ();
count = store.;
count = ( s.);
State 的改变会触发重新渲染,而结构不良的 state 可能会导致远超必要的重新渲染——使应用程序变慢。关键策略:窄化订阅、拆分 state、memoize 以及保持 state 的局部性。
// ❌ subscribing to the whole store → re-renders on ANY change
const store = ();
count = store.;
count = ( s.);
选择性订阅(Zustand/Redux selectors、Jotai atoms)是最强有力的杠杆——组件仅在其特定 slice 改变时重新渲染,而不是在每次 store 更新时都重新渲染。
// ❌ one big context → every consumer re-renders when anything changes
// ✅ separate contexts so unrelated updates don't cross-trigger
<ThemeContext><UserContext>...</UserContext></ThemeContext>
const Item = React.memo(ItemComponent); // skip re-render if props are unchanged
const expensiveValue = useMemo(() => compute(data), [data]);
const handleClick = useCallback(() => doX(id), [id]); // stable function reference
Memoization 防止子组件在其 props(按引用)未改变时重新渲染——但这仅在您同时保持 props/callbacks 引用稳定(因此需要 useCallback/useMemo)并不可变地更新 state 时才有效。
State high in the tree re-renders everything below it.
Move state DOWN to the smallest component that needs it → smaller re-render scope.
// ❌ a new object/array each render breaks memoization downstream
<Child config={{ a: 1 }} /> // new {} every render
// ✅ stable reference
const config = useMemo(() => ({ a: 1 }), []);
const selectActive = createSelector([s => s.items], items => items.filter(i => i.active));
// returns the SAME reference when items didn't change → no needless re-render
React DevTools Profiler / "why did you render" → find what actually re-renders
before optimizing. Premature memoization adds complexity for no gain.
过度重新渲染是导致 React/state-driven 应用程序运行缓慢的主要原因,而这些问题源于 state 的结构方式和订阅方式。
该工具包——窄化的选择性订阅、拆分的 contexts、具有稳定引用的 memoization、不可变更新以及 state 的局部化——直接控制重新渲染的范围。
至关重要的是,您应该进行测量(Profiler)来找到真正的瓶颈,然后再进行优化,因为不谨慎的 memoization 会增加复杂性而不带来任何益处。
理解什么触发重新渲染以及如何控制它们对于构建高性能的大规模应用程序至关重要。