DEV Community

Devanshu Biswas
Devanshu Biswas

Posted on

Context vs Prop Drilling: I Put the Re-render Blast Radius Side by Side

"Prop drilling is bad, use Context" is repeated everywhere — but the actual cost stays abstract. So I put the two approaches side by side with live render counters. Click one button and the difference is impossible to miss.

▶ Live demo: https://context-vs-props-drilling.vercel.app/
Source (React 19 + TS): https://github.com/dev48v/context-vs-props-drilling

Two identical 4-level trees, both React.memo'd. One threads a value down as a prop through every level; the other provides it once via Context and reads it only at the leaf. Change the value:

  • Prop drilling → 4 components re-render. Every component on the path receives the changed prop, so all of them re-render — and each intermediate is cluttered with a value it does nothing with except pass along.
  • Context → 1 component re-renders. The intermediates take no value prop, so they're skipped (memoized, props unchanged). Only the consumer leaf re-renders.

The summary tallies it on every click: 4 vs 1.

Why Context skips the middle

This is the part that surprises people: with Context, an intermediate component can be skipped even though a descendant re-renders.

<ThemeCtx.Provider value={val}>
  <A />          {/* memo, no props → skipped on value change */}
</ThemeCtx.Provider>

const A = memo(() => <B />);   // skipped
const B = memo(() => <C />);   // skipped
const C = memo(() => <Leaf />); // skipped
const Leaf = () => {
  const value = useContext(ThemeCtx); // ← re-renders on context change
  return <div>{value}</div>;
};
Enter fullscreen mode Exit fullscreen mode

React re-renders context consumers directly when the provider value changes — it doesn't need to re-render the components in between. With prop drilling there's no such shortcut: the only way the value reaches the leaf is through every parent, so every parent must re-render.

The catch — Context isn't a free lunch

Context isn't a "no re-renders" button. Every consumer re-renders whenever the provider value changes — there's no built-in selective subscription. One big, chatty context can cause its own over-rendering. The fixes:

  • Split contexts by how often they change (calm AuthContext ≠ chatty MousePositionContext).
  • useMemo the provider value so it doesn't get a new identity on every parent render (a classic bug — it makes all consumers re-render constantly).
  • Use a selector-based store (Zustand, Redux, use-context-selector) when components only care about part of the value.

Why a side-by-side

Reading "Context avoids prop drilling" doesn't tell you it also cuts the wasted renders on the path — or that it can add its own if you're careless. Watching 4 vs 1 tick on every click, and seeing the middle components stay frozen, turns the advice into a model.

Real React, zero UI dependencies. If it helped, a star helps others find it: https://github.com/dev48v/context-vs-props-drilling

Top comments (0)