useContext — share state without prop drilling
The problem: prop drilling
Imagine your app's theme, or the logged-in user. Many components deep in the tree need it. Passing it as a prop through every layer — parent → child → grandchild → … — even through components that do not use it, just to pass it along. This tiresome passing is called prop drilling, and it makes code messy.
Context solves it: put data in one place and let any component read it directly, no matter how deep.
Three steps to use Context
1. Create the context:
import { createContext } from "react";
export const ThemeContext = createContext();
2. Provide a value at the top, wrapping your app:
function App() {
const [theme, setTheme] = useState("dark");
return (
<ThemeContext.Provider value={theme}>
<Page />
</ThemeContext.Provider>
);
}
3. Consume it anywhere below, with useContext:
import { useContext } from "react";
import { ThemeContext } from "./ThemeContext";
function Button() {
const theme = useContext(ThemeContext);
return <button className={theme}>Click</button>;
}
No matter how deep Button is, it reads theme directly — no drilling through every parent.
When should I use Context?
For global-ish data that many components need: the current user, theme, language, or a shopping cart.
A word of caution: do not put everything in Context. For data used by just one or two nearby components, plain props (or lifting state up) are simpler. Context is for truly shared, app-wide data.
Context lets any component read shared data directly, skipping prop drilling. Create it, wrap your app in a
Providerwith a value, and read it withuseContext. Use it for app-wide data like user or theme.