Context API
- React
React's built-in way to share a value with a whole subtree of components without passing props through every level, avoiding prop drilling.
Prerequisites
- Props and one-way data flow (see Related Topics)
What you'll understand
- What problem the Context API solves
- How a provider and useContext work together
- When context is the right tool and when it is not
Explanation
The Context API is React’s built-in mechanism for sharing a value with an entire subtree of components without threading it through props at every level. It exists to solve prop drilling: the tedious, error-prone situation where a value has to be passed down through many intermediate components that do not use it, just to reach one deep down that does.
Context has two halves. A Provider sits high in the tree and supplies a value; any component beneath it, no matter how deep, can read that value directly with the useContext hook, skipping all the intermediate props. Common uses are genuinely global concerns such as the current theme, the current user, or the preferred language, values that many components across the app need.
Context is a distribution tool, not a full state-management solution (see Related Topics), and it has a cost to respect: when a provider’s value changes, every component consuming that context re-renders. So reserve context for data that is truly widely shared and changes relatively infrequently, and do not reach for it to avoid passing props just one or two levels, where a prop is simpler and clearer.
Examples
A provider supplies a value to everything nested inside it:
const ThemeContext = createContext<'light' | 'dark'>('light');
function App() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}A deeply nested component reads it directly, with no prop drilling:
import { useContext } from 'react';
function ThemedButton() {
const theme = useContext(ThemeContext);
return <button className={theme}>Click</button>;
}Common mistakes
- Using context for data that only needs to travel one or two levels.
- Putting frequently changing state in a single context, causing wide re-renders.
- Placing everything in one giant context instead of splitting by concern.
- Reading a context without a matching provider above it, getting the default value unexpectedly.
Best practices
- Use context for genuinely global, infrequently changing values.
- Split unrelated concerns into separate contexts.
- Keep a provider close to the subtree that needs it.
- Reach for a prop when the distance is short; reserve context for real prop drilling.
Further reading
- React, Passing data deeply with context — https://react.dev/learn/passing-data-deeply-with-context
- React, useContext — https://react.dev/reference/react/useContext