Context is React's prop-drilling escape hatch. Use it for things that are genuinely tree-wide (theme, auth, locale) — not for everything that's annoying to thread through three levels.
The three parts
createContext(defaultValue)— returns a Context object (and in React 19, the Context itself is the Provider, no.Providerneeded).- The Provider — wraps a subtree and supplies the current value:
<MyCtx value={...}>. useContext(MyCtx)— reads the nearest provider's value from any descendant.
The default value (the argument to createContext) is what consumers see when no Provider is above them. Use it for nullable defaults; many apps wrap consumers in a hook that throws if the Provider is missing (see code block).
React 19's <Context> as Provider
Before React 19 you'd write <MyCtx.Provider value={...}>. In 19 the Context object can be used directly as the Provider — <MyCtx value={...}>. Both still work; the new syntax is shorter and matches how callers think about the value.
Re-renders
When a Provider's value changes (reference equality), every consumer re-renders. If your value is an object built in render — value={{ theme, setTheme }} — it changes every render and every consumer re-renders. Memoize the object with useMemo, or trust the React Compiler (Track 7) to do it for you.
When to reach for Context
- Theme (light/dark, accent color).
- Auth (current user, login/logout functions).
- Locale and translations.
- Compound-component state (lesson 3 of Track 2 showed this).
- App-wide settings that genuinely need to be tree-wide.
When not to
- Server state (fetched data) — use a query library (TanStack Query) or your own custom hook.
- Frequently-changing values where most consumers don't care — Context will re-render everyone.
- Form state — keep it local or in a Zustand store.