Frontend
medium
mid
How would you isolate which component is re-rendering unnecessarily and fix it
Measure first with the React DevTools Profiler and the 'highlight updates' / why-did-you-render tooling. Identify the cause (unstable props, context, parent re-render), then fix with memoization, state colocation, splitting context, or stabilizing references — not by sprinkling React.memo everywhere.
6 min read·~12 min to think through
Unnecessary re-renders are a measure-then-fix problem. Guessing leads to over-memoization, which adds its own cost and complexity.
Step 1 — Isolate it (measure)
- React DevTools Profiler — record an interaction, look at the flame graph. It shows which components rendered, how long they took, and why each rendered ("props changed", "hooks changed", "parent rendered").
- "Highlight updates when components render" (DevTools settings) — visually flashes re-rendering components. A component flashing on every keystroke that shouldn't = your suspect.
why-did-you-renderlibrary — logs exactly which prop/state reference changed and whether it was deep-equal (i.e. a "fake" change).
Step 2 — Diagnose the cause
Common culprits:
- Parent re-renders → all children re-render (unless memoized).
- Unstable prop references — a new object/array/function literal created in render each time, breaking
React.memo. - Context — every consumer re-renders when any part of the context value changes.
- State too high — state lives in a parent, so a change re-renders a big subtree that didn't need it.
- New
childrenelement identity each render.
Step 3 — Fix the actual cause
- Colocate state — move state down to the component that uses it. The cheapest fix; often eliminates the problem entirely.
useMemo/useCallback— stabilize object/array/function props passed to memoized children. Only meaningful if the child is actually memoized.React.memo— memoize a component whose props rarely change but whose parent re-renders often.- Split context — separate fast-changing and slow-changing values into different providers; or pass setters via a stable context separate from the value.
- Lift content via
children— a parent that re-renders for its own state doesn't re-renderchildrenpassed in from above. - Selector-based stores (Zustand/Redux) — subscribe to slices, not the whole store.
The discipline
Don't memoize preemptively. React.memo and useMemo have a cost (comparison + memory) and clutter the code. Memoize where the profiler shows a real, repeated, expensive re-render. React Compiler (when adopted) auto-memoizes and changes this calculus.
Follow-up questions
- •Why can React.memo still re-render even when you wrap a component in it?
- •When is useMemo/useCallback actually doing nothing useful?
- •How does the children prop pattern avoid re-renders?
- •How does React Compiler change the memoization story?
Common mistakes
- •Sprinkling React.memo/useMemo everywhere without measuring.
- •Memoizing a component while still passing it a fresh object/function prop each render.
- •Putting fast-changing values in a wide context.
- •Keeping state high in the tree when it could be colocated.
Performance considerations
- •Memoization isn't free — it costs a comparison and memory. The win has to outweigh that. Profile to confirm a re-render is both frequent and expensive before optimizing. Colocation is usually cheaper and cleaner than memoization.
Edge cases
- •A memoized component with children — children identity changes each render.
- •Re-renders that are cheap and harmless (don't optimize those).
- •Lists where every row re-renders because the row component isn't memoized.
- •Inline-defined components recreated every render.
Real-world examples
- •A search input that re-rendered an entire results grid on each keystroke — fixed by colocating the input state.
- •A theme context bundling theme + a frequently-updated value, split into two providers.
Senior engineer discussion
Seniors lead with measurement (Profiler, why-did-you-render) and treat memoization as a targeted fix, not a default. They name the structural fixes first — colocation, children-as-props, context splitting — because those remove the problem rather than masking it, and they mention React Compiler shifting manual memoization toward obsolescence.
Related questions
Frontend
Medium
6 min
Frontend
Easy
6 min