Home/Learn/React/Diagnosing Unnecessary Re-renders

Diagnosing Unnecessary Re-renders

Advanced
Performance

Find the cause before applying a fix. Nearly every "React is slow" report turns out to be one of four specific causes, and three of them are fixed by moving code rather than memoising it.

Overview

Performance work in React starts with a diagnosis, because the fixes look similar and the causes do not. A re-render itself is not the problem — a re-render that runs an expensive computation, or that cascades into hundreds of components, is. The four causes worth recognising on sight are state placed too high, a context whose value changes on every render, an unstable prop defeating memo, and a genuinely expensive render. Each has a different fix, and reaching for useMemo before knowing which one you have is how codebases end up memoised everywhere and still slow.

The Four Causes

Recognise the shape, then apply the matching fix.

Four causes, three structural fixes
// 1. State too high — a keystroke in a search box re-renders a
//    2,000-row table that does not read the query
function Page() {
  const [query, setQuery] = useState('')     // move this into SearchBox
  return <><SearchBox value={query} onChange={setQuery} /><BigTable /></>
}
// Fix: move the state down, or pass BigTable as children.

// 2. Context value recreated every render
<Ctx.Provider value={{ user, signOut }}>    // new object each time
// Fix: useMemo the value; split contexts.

// 3. Unstable prop defeating memo
<MemoRow onSelect={() => pick(id)} />        // new function each render
// Fix: useCallback, or pass the id and a stable handler.

// 4. Genuinely expensive render — a big list, a chart, a heavy
//    markdown or syntax-highlighting pass
// Fix: useMemo the computation, virtualise the list, or split the
//      work with useDeferredValue.

// Causes 1-3 are fixed by structure. Only 4 needs memoisation.

Finding It

Tools, in the order you should use them.

Highlight, profile, then measure
// 1. React DevTools -> "Highlight updates when components render"
//    Visual, instant, and usually enough. Type one character and
//    watch what flashes.

// 2. Profiler tab: record the interaction, read the flame chart
//    for actual render duration, and enable "Record why each
//    component rendered" — it names props, state, hooks or parent.

// 3. In code, when you need it in a specific place
useEffect(() => { console.count('ProblemRow render') })

// 4. The Profiler component, for measuring in production builds
<Profiler id="list" onRender={(id, phase, actualDuration) => {
  if (actualDuration > 16) report(id, actualDuration)
}}>

// Remember StrictMode doubles renders in development — halve the
// counts, or check in a production build, before concluding anything.

// And measure on a mid-range device with CPU throttling. A laptop
// hides problems that a ₹12,000 Android phone does not.

Structural Fixes

The two moves that solve most cases without memoisation.

Move state down; pass children through
// Move state down — the expensive sibling no longer re-renders
function Page() {
  return <><SearchBox /><BigTable /></>       // SearchBox owns its state
}

// Pass expensive children as a prop or as children — the element is
// created by the grandparent, so this component's render does not
// recreate it
function Layout({ children }) {
  const [open, setOpen] = useState(false)     // toggling does NOT
  return <div>{children}</div>                // re-render children
}
<Layout><ExpensiveTree /></Layout>

// Both work because React compares element identity: unchanged
// children are the same object, so their subtree is skipped.

// Only after these, consider memo + useCallback + useMemo — and
// apply them to the specific component the profiler named, not
// across the file.

Key Points to Remember

  • 1A re-render is only a problem when it is expensive or cascades widely — measure before optimising
  • 2The four causes are state too high, an unmemoised context value, an unstable prop defeating memo, and genuinely expensive work
  • 3Highlight-updates and the Profiler's "why did this render" identify the cause in seconds
  • 4Moving state down and passing children through fix most cases with no memoisation at all
  • 5StrictMode doubles development renders — verify counts in a production build, on a throttled mid-range device

Interview Questions

Sign in to ask Aria
1

How would you find out why a component re-renders too often?

Medium
2

Why does passing an expensive component as children prevent it re-rendering?

Hard
3

A search input makes a large table lag on every keystroke. What is your first fix?

Medium

Ask Aria about Diagnosing Unnecessary Re-renders

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…