Identify which components need memoization and justify why.
Memoize a component when it re-renders often (parent re-renders frequently), its props are stable or can be made stable, and its render is non-trivial. Don't memoize cheap components, ones whose props change every render anyway, or as a blanket policy. Always profile first.
Memoization isn't free — React.memo adds a props comparison and memory cost, and useMemo/useCallback add their own overhead and clutter. So the question is genuinely "which components" — and the answer is measure, then memoize the ones that actually benefit.
A component benefits from React.memo when ALL three are true
- It re-renders often without needing to — usually because its parent re-renders frequently (parent state changes, context updates) even though this component's own data didn't change.
- Its props are stable, or can be made stable — if the parent passes a fresh object/array/function literal every render,
React.memocompares them as different and re-renders anyway. So you often needuseMemo/useCallbackin the parent for memo to do anything. - Its render is non-trivial — the component (or its subtree) is genuinely expensive to render. Memoizing a component that renders one
<span>saves nothing and costs the comparison.
Strong candidates
- List/row items —
<Row>in a big list: the list re-renders, but each row's data is unchanged → memoizeRow, keyed by id. Huge win. - Expensive subtrees — a chart, a heavy widget, a complex card — that sit under a frequently-re-rendering parent.
- Components receiving stable props but whose parent re-renders for unrelated reasons.
- Pure presentational components with simple, stable props and meaningful render cost.
Poor candidates — don't memoize these
- Cheap components — the comparison costs more than the re-render saved.
- Components whose props change every render anyway — memo just adds a failed comparison each time.
- Components that rarely re-render — nothing to save.
- As a blanket "memo everything" policy — adds overhead and noise app-wide for marginal benefit.
useMemo / useCallback — same discipline
useCallbacka function only if it's passed to a memoized child or used as an effect dependency — otherwise it does nothing useful.useMemoa computation only if it's genuinely expensive, or its result is a prop to a memoized child / an effect dep.- A
useMemoover a trivial calculation is pure overhead.
The process — profile first
- React DevTools Profiler + "highlight updates" +
why-did-you-render— find what actually re-renders frequently and expensively. - For each hot component, check: does it re-render unnecessarily? Are its props stable (or fixable)? Is its render costly?
- Often the better fix isn't memo at all — colocate state, split contexts, pass content via
children. Those remove the re-render rather than skipping it. - Memoize the remaining real hot spots; verify the improvement in the Profiler.
- Note: React Compiler auto-memoizes — where adopted, manual memoization becomes largely unnecessary.
How to answer
"I memoize a component only when it re-renders frequently for no reason — usually a frequently-re-rendering parent — and its props are stable or can be made stable, and its render is non-trivial. Classic case: row items in a large list. I don't memoize cheap components, ones whose props change every render anyway, or as a blanket policy — memo has a cost. And I profile first: often the real fix is colocating state or splitting context, which removes the re-render instead of just skipping it."
Follow-up questions
- •Why can React.memo still re-render a component you wrapped in it?
- •When is useCallback actually doing nothing useful?
- •What's the cost of over-memoizing?
- •What structural fixes remove re-renders instead of skipping them?
Common mistakes
- •Memoizing everything as a blanket policy.
- •Wrapping a component in React.memo while still passing it fresh object/function props.
- •Memoizing cheap components where the comparison costs more than the render.
- •useCallback/useMemo on values not passed to memoized children or used as deps.
- •Memoizing without profiling — guessing at hot spots.
Performance considerations
- •React.memo trades a props comparison + memory for skipped renders — worth it only when the skipped render is frequent and expensive. Over-memoization adds overhead and code noise everywhere for marginal gain. Structural fixes (colocation, context splitting) are often cheaper and cleaner.
Edge cases
- •A memoized component with children — children identity changes each render.
- •Custom comparison functions in React.memo (rarely worth it).
- •Context consumers — memo doesn't stop context-driven re-renders.
- •React Compiler making manual memoization obsolete.
Real-world examples
- •Memoized <Row> in a large/virtualized list so a list update doesn't re-render every visible row.
- •A memoized chart component under a parent that re-renders on unrelated state.