Stop Unnecessary Re-renders in React
React re-renders a component when state, props, or context changes. That behavior is fundamental to how React keeps UI consistent with data.
Most re-renders are totally fine. The re-renders that hurt are the ones that repeatedly run expensive work, or force large subtrees to repaint when nothing meaningful changed for that part of the UI.
Impact: smoother interactions and lower CPU usage in complex UIs
Rule 1 — Lazy state initialization
If initial state setup is expensive, initialize lazily.
With lazy initialization, React calls the initializer callback only for the initial state setup, not during subsequent renders.
DevTools Profiler screenshot description
- Before: render flamegraph shows repeated self-time in
JSON.parse. - After: parse cost appears only in the initial commit.
Rule 2 — Stabilize callback references
A memoized child still re-renders if it receives a new function reference every render.
React.memo only helps when props are stable references.
DevTools Profiler screenshot description
- Before: child commits on every parent render.
- After: child commits only when
idchanges.
Rule 3 — Memoize expensive derivations
If you repeatedly sort/filter big collections, compute once per dependency change.
Rule of thumb: memoize only if a computation costs more than ~1ms and profiling confirms it.
Rule 4 — Stable object/array literals in props
Object and array literals create new references on every render.
Stable references reduce avoidable memoized-child updates.
Rule 5 — Split context to avoid blast radius
A giant context causes broad re-renders because any value change updates all consumers.
This limits re-render blast radius: auth changes should not repaint theme-only consumers.
React Compiler note (React 19)
If you are on React 19 with the React Compiler enabled, rules 3 and 4 are often automated by compile-time memoization.
Rules 1, 2, and 5 still apply and remain important architectural practices.
When NOT to optimize
Do not optimize by default "just in case." Start with the React DevTools Profiler and production-like scenarios, then optimize the top offenders. Premature optimization adds complexity, increases bug risk, and can make code harder for teams to maintain.
Prefer this order:
- Measure first
- Optimize targeted bottlenecks
- Re-measure to confirm impact