Context lets any component in the tree read a value without passing it through every level as props. It solves prop drilling for data like the current user, theme, or locale — values that many components need but few intermediate components care about. It is not a state manager, and treating it like one is the most common mistake teams make.
Master react context api
Take the React Intermediate course with hands-on lessons and challenges.
The three-step pattern: create the context, wrap a subtree with the provider, consume via a custom hook. The value is memoized so consumers only re-render when the theme actually changes, not when the provider's parent re-renders for unrelated reasons.
Auth state changes rarely (login, logout) and is needed across the entire app — a textbook Context use case. The login and logout callbacks are stable references via useCallback, so the memoized value only changes when the user object changes.
React 19 simplified the provider API. You no longer need .Provider — just render the context itself as a JSX element with a value prop. The old syntax still works but is considered legacy. If you are starting a new project on React 19, use the shorter form.
A toast notification system is a good split context example. Buttons that trigger toasts only need dispatch — they should not re-render when the toast list changes. The toast display component reads state. Splitting avoids wasted renders in every component that calls useToastDispatch.
Feature flags are fetched once and rarely change during a session, making them ideal for Context. The useFeatureFlag hook provides a clean boolean API. Components conditionally render features without knowing how flags are loaded or stored.
Real applications have multiple contexts. Wrapping them in an AppProviders component keeps the app root readable and makes provider order explicit. Provider order matters when inner providers depend on values from outer ones.
Putting everything in a single context — user data, theme, cart, and notifications in one big object, causing every consumer to re-render on any change
Create one context per domain (AuthContext, ThemeContext, CartContext, etc.). Each context triggers re-renders only in its own consumers. This follows the single-responsibility principle and is the most impactful performance optimization for Context.
Creating a new value object on every render — writing `<MyContext value={{ user, theme }}>` directly in JSX without memoization
Wrap the value in `useMemo`: `const value = useMemo(() => ({ user, theme }), [user, theme])`. Without this, every parent re-render creates a new object reference, which forces all consumers to re-render even if the data has not changed.
Using Context for frequently updating data like form input values, scroll position, or animation frames — this re-renders the entire consumer tree on every change
Keep high-frequency state local with `useState` in the component that owns it. If multiple components need fast-changing shared state, use Zustand (selector-based subscriptions) or Jotai (atomic updates) instead of Context.
Calling `useContext(SomeContext)` directly without checking for null — when the default value is `null`, components outside the provider silently get `null` and crash later with a confusing error
Always create a custom hook that checks for null and throws a descriptive error: `if (!ctx) throw new Error('useAuth must be used within AuthProvider')`. This catches misconfiguration immediately during development.
React Context solves prop drilling by broadcasting a value to all descendants in the tree. In React 19, you render the context directly as a JSX element without the .Provider wrapper. The three-step pattern — create with createContext, provide with a value prop, consume via a custom hook — covers every use case. Context re-renders all consumers on any value change, so keep context values focused (one per domain), memoize them, and split state from dispatch when needed. For data that changes often or requires fine-grained subscriptions, use a dedicated state library instead.
Interactive lessons and challenges on Stanza, practice in VS Code, Cursor, or the web.
Interactive lessons and challenges, right in your code editor.
Check the free courses. No credit card.