Context API
The shopping cart project briefly used Context to solve a real problem: a header badge, a product grid, and a cart page all needing the same data despite sitting nowhere near each other in the component tree. This chapter covers that mechanism properly — Context as React's built-in answer to the prop-drilling problem first raised back in Fundamentals Chapter 10.
The Three Pieces
createContext(null) creates the context object itself, separately from any actual data — the null is just a fallback default. <ThemeContext.Provider value={...}> makes that value available to everything nested inside it; ThemeButton can sit any number of components below App — even with several unrelated components in between — and still reach the same theme/setTheme directly via useContext(ThemeContext), without a single one of those in-between components ever mentioning theme at all.
Providing State and Functions Together
The shopping cart project's pattern — bundling state and the functions that update it into one object passed to value — is the standard shape for a real context, not just a single raw value. It's common enough to extract the whole thing into its own dedicated "provider" component, exactly as CartProvider did:
ThemeProvider wraps {children} (the composition pattern from Fundamentals Chapter 9) rather than rendering anything visible itself — its entire job is owning the state and exposing it, leaving every consumer free to use it however it wants.
A Custom Hook for Cleaner Consumption
Wrapping useContext(ThemeContext) in a small custom hook is an extremely common pattern in real codebases — it means every consumer imports one clearly-named function (useTheme) instead of needing to know the underlying context object exists at all. Custom hooks get their own full treatment next chapter; this is a first glimpse of how naturally they pair with Context specifically.
value changes — for state that changes rarely (theme, the logged-in user, locale), that's entirely fine. For state that changes very frequently (every keystroke, every animation frame), Context can cause far more re-rendering than passing props directly to just the few components that need it. When in doubt: reach for lifting state up first, and only bring in Context once prop drilling genuinely becomes painful, exactly as Fundamentals Chapter 10 first suggested.
| Situation | Reach for... |
|---|---|
| A few nearby components share state | Lifting state up (props) |
| Many distant components need the same rarely-changing value | Context |
| State changes very frequently and widely consumed | A dedicated state library (Advanced Ch 1) |
Coding Challenges
Build a ThemeContext with a ThemeProvider holding theme ("light"/"dark") and a toggleTheme function. Consume it in at least two unrelated components (e.g. a Header and a Footer) so both reflect the same theme and both have a way to toggle it.
📄 View solutionBuild an AuthContext storing a user (null when logged out, an object like { name } when logged in) plus login and logout functions. Consume it in a Header (showing "Welcome, [name]" or a login button) and a separate Dashboard component (showing content only when a user is logged in).
📄 View solutionTake your ThemeContext from Challenge 1 and write a useTheme custom hook wrapping useContext(ThemeContext). Refactor every consumer to call useTheme() instead of useContext(ThemeContext) directly.
📄 View solutionChapter 2 Quick Reference
- createContext(default) — creates the context object itself
- <Context.Provider value={...}> — makes a value available to every nested consumer
- useContext(Context) — reads that value, from any depth, with no props passed through
- Bundle state + its updater functions into one
valueobject — the standard shape for a real context - A small custom hook (
useTheme) wrappinguseContextis a common, cleaner consumption pattern - Context re-renders every consumer on change — best for rarely-changing, widely-needed values, not high-frequency state
- Next chapter: useReducer — managing more complex state transitions with a single dispatch function