Back to React
React
medium
mid

How do you decide which React components actually need memoization?

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.

6 min read·~10 min to think through

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

  1. 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.
  2. Its props are stable, or can be made stable — if the parent passes a fresh object/array/function literal every render, React.memo compares them as different and re-renders anyway. So you often need useMemo/useCallback in the parent for memo to do anything.
  3. 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 → memoize Row, 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

  • useCallback a function only if it's passed to a memoized child or used as an effect dependency — otherwise it does nothing useful.
  • useMemo a computation only if it's genuinely expensive, or its result is a prop to a memoized child / an effect dep.
  • A useMemo over a trivial calculation is pure overhead.

The process — profile first

  1. React DevTools Profiler + "highlight updates" + why-did-you-render — find what actually re-renders frequently and expensively.
  2. For each hot component, check: does it re-render unnecessarily? Are its props stable (or fixable)? Is its render costly?
  3. 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.
  4. Memoize the remaining real hot spots; verify the improvement in the Profiler.
  5. 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.

Senior engineer discussion

Seniors give the three-condition test (re-renders often + stable props + non-trivial render), name list rows as the canonical case, and are explicit that memo has a cost so blanket memoization is wrong. The senior signal is profiling first and preferring structural fixes (colocation, context splitting, children-as-props) that eliminate the re-render rather than skip it — plus noting React Compiler.

Related questions