react-component-performance

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

React 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

工作流程

  1. Reproduce or describe the slowdown.
  2. Identify what triggers re-renders (state updates, props churn, effects).
  3. Isolate fast-changing state from heavy subtrees.
  4. Stabilize props and handlers; memoize where it pays off.
  5. Reduce expensive work (computation, DOM size, list length).
  6. 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.
  1. 复现或描述卡顿场景
  2. 定位触发重渲染的原因(状态更新、props频繁变动、副作用)
  3. 将快速变化的状态与重负载子树隔离
  4. 稳定props和事件处理函数,在收益明确的场景下使用 memo 优化
  5. 减少高开销任务(计算量、DOM体积、列表长度)
  6. 验证:打开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
    memo
    only when props are stable.
  • Stabilize props: use
    useCallback
    /
    useMemo
    for handlers and derived values.
  • 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:对事件处理函数和衍生值使用
    useCallback
    /
    useMemo
  • 避免渲染过程中的衍生计算:提前计算,或者在记忆化的辅助函数中计算
  • 控制列表尺寸:对长列表使用窗口化/虚拟滚动,避免渲染隐藏元素
  • 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

使用
useCallback
+
memo
稳定回调函数

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} />);
}
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

性能分析验证步骤

  1. Open React DevTools → Profiler tab.
  2. Click Record, perform the slow interaction, then Stop.
  3. Switch to Flamegraph view; any bar labeled with a component and time > ~16 ms is a candidate.
  4. Use Ranked chart to sort by self render time and target the top offenders.
  5. Apply one optimization at a time, re-record, and compare render counts and durations against the baseline.
  1. 打开React DevTools → Profiler标签页
  2. 点击录制,执行触发卡顿的交互,然后点击停止
  3. 切换到Flamegraph视图,所有标注组件名且时长超过约16 ms的柱状条都是优化候选
  4. 使用Ranked chart按自身渲染时长排序,优先优化最耗时的组件
  5. 每次仅应用一项优化,重新录制,将渲染次数和时长与基线数据对比

Example Reference

示例参考

Load
references/examples.md
when the user wants a concrete refactor example.
当用户需要具体的重构示例时,加载
references/examples.md
文件。