Lesson 17 / 25

Context

Data available to a whole subtree.

Provider above, useContext below

Context lets a parent make a value available to every component below it without passing props through each layer (prop drilling). Create it with createContext(default), provide a value higher in the tree (in React 19 you can render <MyContext value={...}> directly; earlier versions use <MyContext.Provider>), and read it with useContext. Good uses: theme, current user, locale. Avoid putting rapidly changing values in a widely used context, since every consumer re-renders when it changes.

Context, custom hooks and refs

Avoid prop drilling with context, reuse stateful logic with custom hooks, and reach the DOM with refs.

Three ideas: context, custom hooks, refs.
Figure 6.1 — Context, custom hooks and refs.

A theme without prop drilling, run

I ran this with React 19.3 and react-dom 19.3 on Node.js 22, compiling JSX with esbuild 0.28. Browser-style examples use jsdom 29 as a fake DOM (imported from a small setup-dom.mjs file) and act() to apply updates. Without a provider, the button uses the default "light" theme; wrapped in a dark provider, the same Toolbar renders a "btn-dark" button, even though Toolbar never passes a theme prop.

import { createContext, useContext } from "react";
import { renderToStaticMarkup } from "react-dom/server";

const ThemeContext = createContext("light");          // default when no provider is above
function Button({ children }) {
  const theme = useContext(ThemeContext);
  return <button className={`btn-${theme}`}>{children}</button>;
}
function Toolbar() { return <div><Button>Save</Button></div>; }   // no theme prop passed through
console.log(renderToStaticMarkup(<Toolbar />));
console.log(renderToStaticMarkup(<ThemeContext value="dark"><Toolbar /></ThemeContext>));

Output:

<div><button class="btn-light">Save</button></div>
<div><button class="btn-dark">Save</button></div>

Split contexts by change frequency

Keep slow-changing values (theme, user) separate from fast-changing ones to limit re-renders.

Quick check: What problem does context solve?

  • Styling components
  • Fetching data from APIs
  • Passing data through many intermediate components (prop drilling)
  • Speeding up every render
Answer

Passing data through many intermediate components (prop drilling) — Share values with a subtree.