react-component-performance
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseReact Component Performance
React 组件性能优化
Overview
概述
Identify render hotspots, isolate expensive updates, and apply targeted optimizations without changing UI behavior.
定位渲染热点,隔离高开销更新,在不改变UI行为的前提下应用针对性优化方案。
When to Use
适用场景
- When the user asks to profile or improve a slow React component.
- When you need to reduce re-renders, list lag, or expensive render work in React UI.
- 用户要求分析或优化运行缓慢的React组件时
- 你需要减少React UI中的重复渲染、列表卡顿或高开销渲染任务时
Workflow
工作流程
- Reproduce or describe the slowdown.
- Identify what triggers re-renders (state updates, props churn, effects).
- Isolate fast-changing state from heavy subtrees.
- Stabilize props and handlers; memoize where it pays off.
- Reduce expensive work (computation, DOM size, list length).
- Validate: open React DevTools Profiler → record the interaction → inspect the Flamegraph for components rendering longer than ~16 ms → compare against a pre-optimization baseline recording.
- 复现或描述卡顿场景
- 定位触发重渲染的原因(状态更新、props频繁变动、副作用)
- 将快速变化的状态与重负载子树隔离
- 稳定props和事件处理函数,在收益明确的场景下使用 memo 优化
- 减少高开销任务(计算量、DOM体积、列表长度)
- 验证:打开React DevTools Profiler → 记录交互过程 → 检查火焰图中渲染时长超过约16 ms的组件 → 与优化前的基线记录做对比
Checklist
检查清单
- Measure: use React DevTools Profiler or log renders; capture baseline.
- Find churn: identify state updated on a timer, scroll, input, or animation.
- Split: move ticking state into a child; keep heavy lists static.
- Memoize: wrap leaf rows with only when props are stable.
memo - Stabilize props: use /
useCallbackfor handlers and derived values.useMemo - Avoid derived work in render: precompute, or compute inside memoized helpers.
- Control list size: window/virtualize long lists; avoid rendering hidden items.
- Keys: ensure stable keys; avoid index when order can change.
- Effects: verify dependency arrays; avoid effects that re-run on every render.
- Style/layout: watch for expensive layout thrash or large Markdown/diff renders.
- 量化指标:使用React DevTools Profiler或打印渲染日志,获取优化前的基线数据
- 查找变动源:定位在定时器、滚动、输入、动画场景下触发更新的状态
- 拆分逻辑:将频繁变动的状态移到子组件中,保持重负载列表静态化
- 记忆化优化:仅当props稳定时,使用包裹叶子节点行组件
memo - 稳定props:对事件处理函数和衍生值使用/
useCallbackuseMemo - 避免渲染过程中的衍生计算:提前计算,或者在记忆化的辅助函数中计算
- 控制列表尺寸:对长列表使用窗口化/虚拟滚动,避免渲染隐藏元素
- Keys:确保key稳定,当列表顺序可能变化时不要使用索引作为key
- 副作用:检查依赖数组,避免每次渲染都重新执行的副作用
- 样式/布局:注意高开销的布局抖动,或者大量Markdown/差异内容渲染的问题
Optimization Patterns
优化模式
Isolate ticking state
隔离频繁变动的状态
Move a timer or animation counter into a child so the parent list never re-renders on each tick.
tsx
// ❌ Before – entire parent (and list) re-renders every second
function Dashboard({ items }: { items: Item[] }) {
const [tick, setTick] = useState(0);
useEffect(() => {
const id = setInterval(() => setTick(t => t + 1), 1000);
return () => clearInterval(id);
}, []);
return (
<>
<Clock tick={tick} />
<ExpensiveList items={items} /> {/* re-renders every second */}
</>
);
}
// ✅ After – only <Clock> re-renders; list is untouched
function Clock() {
const [tick, setTick] = useState(0);
useEffect(() => {
const id = setInterval(() => setTick(t => t + 1), 1000);
return () => clearInterval(id);
}, []);
return <span>{tick}s</span>;
}
function Dashboard({ items }: { items: Item[] }) {
return (
<>
<Clock />
<ExpensiveList items={items} />
</>
);
}将定时器或动画计数器移到子组件中,这样父级列表不会在每次状态更新时都重新渲染。
tsx
// ❌ Before – entire parent (and list) re-renders every second
function Dashboard({ items }: { items: Item[] }) {
const [tick, setTick] = useState(0);
useEffect(() => {
const id = setInterval(() => setTick(t => t + 1), 1000);
return () => clearInterval(id);
}, []);
return (
<>
<Clock tick={tick} />
<ExpensiveList items={items} /> {/* re-renders every second */}
</>
);
}
// ✅ After – only <Clock> re-renders; list is untouched
function Clock() {
const [tick, setTick] = useState(0);
useEffect(() => {
const id = setInterval(() => setTick(t => t + 1), 1000);
return () => clearInterval(id);
}, []);
return <span>{tick}s</span>;
}
function Dashboard({ items }: { items: Item[] }) {
return (
<>
<Clock />
<ExpensiveList items={items} />
</>
);
}Stabilize callbacks with useCallback
+ memo
useCallbackmemo使用useCallback
+ memo
稳定回调函数
useCallbackmemotsx
// ❌ Before – new handler reference on every render busts Row memo
function List({ items }: { items: Item[] }) {
const handleClick = (id: string) => console.log(id); // new ref each render
return items.map(item => <Row key={item.id} item={item} onClick={handleClick} />);
}
// ✅ After – stable handler; Row only re-renders when its own item changes
const Row = memo(({ item, onClick }: RowProps) => (
<li onClick={() => onClick(item.id)}>{item.name}</li>
));
function List({ items }: { items: Item[] }) {
const handleClick = useCallback((id: string) => console.log(id), []);
return items.map(item => <Row key={item.id} item={item} onClick={handleClick} />);
}tsx
// ❌ Before – new handler reference on every render busts Row memo
function List({ items }: { items: Item[] }) {
const handleClick = (id: string) => console.log(id); // new ref each render
return items.map(item => <Row key={item.id} item={item} onClick={handleClick} />);
}
// ✅ After – stable handler; Row only re-renders when its own item changes
const Row = memo(({ item, onClick }: RowProps) => (
<li onClick={() => onClick(item.id)}>{item.name}</li>
));
function List({ items }: { items: Item[] }) {
const handleClick = useCallback((id: string) => console.log(id), []);
return items.map(item => <Row key={item.id} item={item} onClick={handleClick} />);
}Prefer derived data outside render
优先在渲染流程外处理衍生数据
tsx
// ❌ Before – recomputes on every render
function Summary({ orders }: { orders: Order[] }) {
const total = orders.reduce((sum, o) => sum + o.amount, 0); // runs every render
return <p>Total: {total}</p>;
}
// ✅ After – recomputes only when orders changes
function Summary({ orders }: { orders: Order[] }) {
const total = useMemo(() => orders.reduce((sum, o) => sum + o.amount, 0), [orders]);
return <p>Total: {total}</p>;
}tsx
// ❌ Before – recomputes on every render
function Summary({ orders }: { orders: Order[] }) {
const total = orders.reduce((sum, o) => sum + o.amount, 0); // runs every render
return <p>Total: {total}</p>;
}
// ✅ After – recomputes only when orders changes
function Summary({ orders }: { orders: Order[] }) {
const total = useMemo(() => orders.reduce((sum, o) => sum + o.amount, 0), [orders]);
return <p>Total: {total}</p>;
}Additional patterns
其他优化模式
- Split rows: extract list rows into memoized components with narrow props.
- Defer heavy rendering: lazy-render or collapse expensive content until expanded.
- 拆分列表行:将列表行提取为props范围更窄的记忆化组件
- 延迟重负载渲染:对高开销内容采用懒加载,或者在展开前保持折叠状态
Profiling Validation Steps
性能分析验证步骤
- Open React DevTools → Profiler tab.
- Click Record, perform the slow interaction, then Stop.
- Switch to Flamegraph view; any bar labeled with a component and time > ~16 ms is a candidate.
- Use Ranked chart to sort by self render time and target the top offenders.
- Apply one optimization at a time, re-record, and compare render counts and durations against the baseline.
- 打开React DevTools → Profiler标签页
- 点击录制,执行触发卡顿的交互,然后点击停止
- 切换到Flamegraph视图,所有标注组件名且时长超过约16 ms的柱状条都是优化候选
- 使用Ranked chart按自身渲染时长排序,优先优化最耗时的组件
- 每次仅应用一项优化,重新录制,将渲染次数和时长与基线数据对比
Example Reference
示例参考
Load when the user wants a concrete refactor example.
references/examples.md当用户需要具体的重构示例时,加载文件。
references/examples.md