call(back)

Predict the Output: Nested Context Providers

What does this render? Explain why.

const Theme = createContext("light");

const Label = memo(function Label() {
  return <span>{useContext(Theme)} </span>;
});

function App() {
  return (
    <>
      <Label />
      <Theme.Provider value="dark">
        <Label />
        <Theme.Provider value="blue">
          <Label />
        </Theme.Provider>
      </Theme.Provider>
    </>
  );
}

Hints

Hint 1

The default passed to createContext is used only when there is no provider above the component.

Hint 2

Which provider is nearest above each Label — and what does memo do, or not do, when a context value changes?

Solution

Show the approach

Answer: light dark blue

  • The default passed to createContext applies only when no provider is above the component.
  • The nearest provider wins.
  • memo does not block context updates. Every consumer re-renders when its provider's value changes by Object.is, so an inline object as value re-renders every consumer on every parent render — which is why provider values are usually wrapped in useMemo, and the functions inside them in useCallback.

Asked at