Diagnosing Unnecessary Re-renders
AdvancedFind 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.
// 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.
// 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 — 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 AriaHow would you find out why a component re-renders too often?
Why does passing an expensive component as children prevent it re-rendering?
A search input makes a large table lag on every keystroke. What is your first fix?
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.