Sikau

React patterns at scale · Day 4 · about 35 min

Context without re-render storms

Split state from actions and keep values stable.

Add one momo, re-render the whole shop

Context cures prop drilling — the field guide's chapter on state management shows how passing a value through five components that don't use it makes every change touch all five files. So teams put the cart in context. Then the profiler shows something odd: clicking Add re-renders every *Add* button, the header, the footer… every component that reads the cart context, even the ones that only ever call add.

Context isn't slow, but it has one simple rule, and at scale you have to design around it. Learn the rule and three small techniques, and a provider can sit at the top of a large app without causing re-render storms.

The rule: a new value re-renders every consumer

When a provider's value changes, React re-renders every component that calls useContext for that context — no matter which part of the value it uses. "Changes" means referential equality: React compares the old and new value with Object.is. An object literal written in render is a brand-new object every time, so this provider tells every consumer "changed!" on every render:

function CartProvider({ children }) {
  const [items, setItems] = useState([]);
  const add = (name) => setItems((list) => [...list, name]);
  return (
    <CartContext.Provider value={{ items, add }}>
      {children}
    </CartContext.Provider>
  );
}

The children prop is your friend: elements passed in from above are the same objects on every provider render, so React skips them unless they read the context. Keep providers small and pass the tree through children.

The rest of this lesson

  • Split, stabilise, selectexplain
  • Inside memopredict
  • Stable actionsfill
  • Which fix?match
  • Calm the cartwrite code
  • Badge quizquiz
  • What you learnedrecap

Continue this lesson free — run real code in your browser

Continue with Google

See all 10 lessons of React patterns at scale