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.
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.