The React Context API lets a parent component broadcast data—such as the active theme, signed-in user, or language preference—to any descendant below it without passing props through every intermediate layer. Context solves "prop drilling," where middle components forward props they never read themselves.
In React 19, you create a context with createContext(defaultValue) and render the context object directly as <ThemeContext value={...}> (or <ThemeContext.Provider value={...}> for React 18 compatibility).
import { createContext, useContext, useState } from 'react';
const ThemeContext = createContext('light');
export function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
const toggleTheme = () => setTheme((t) => (t === 'light' ? 'dark' : 'light'));
return (
<ThemeContext value={{ theme, toggleTheme }}>
{children}
</ThemeContext>
);
}
export function ThemeButton() {
const { theme, toggleTheme } = useContext(ThemeContext);
return (
<button type="button" onClick={toggleTheme}>
Active theme: {theme}
</button>
);
}
flowchart TD
Provider["ThemeProvider (holds state)"] -.->|"Context bypasses middle layers"| Button["ThemeButton (reads useContext)"]
Provider --> Shell["LayoutShell (no theme prop needed)"]
Shell --> Sidebar["Sidebar (no theme prop needed)"]
Sidebar --> Button
Context is ideal for low-frequency global values like auth user, locale, or theme. Avoid placing rapidly updating state (like mouse coordinates or keystroke-by-keystroke form inputs) in one giant app-wide Context, because every consumer component re-renders whenever the value reference changes.
value: Writing value={{ theme, setTheme }} creates a new object every time the Provider re-renders, forcing every consumer to re-render even when theme did not change. Wrap the object in useMemo or split data and dispatch into two contexts.children—keeps components easier to reuse than wiring up a global Context.For simple themes, auth state, or feature flags, yes. For high-frequency state updates with complex selectors and middleware, dedicated state libraries or split contexts scale better.
useContext runs outside a Provider?React returns the fallback defaultValue passed into createContext(defaultValue). Throwing a helpful error inside a custom hook when context is null catches missing providers early.
use(ThemeContext) API?React 19 adds use(Context), which reads context just like useContext and can also be called conditionally inside if statements or loops.
Sign in to track your learning journey, earn industry-recognized certificates, and join our elite developer community.
Quick Access With