Sharing State with useContext
Share data across many components without passing props down every level (“prop drilling”).
What you will learn
- Create a context
- Provide and consume context
- Avoid prop drilling
The prop-drilling problem
Passing a prop through many layers just to reach a deep component is tedious (“prop drilling”). Context lets you share a value with any component beneath a provider, directly.
const ThemeContext = createContext();
function Toolbar() {
const theme = useContext(ThemeContext); // read from anywhere below
return <p>Current theme: <b>{theme}</b></p>;
}
function App() {
return (
<ThemeContext.Provider value="dark">
<h3>App</h3>
<Toolbar />
</ThemeContext.Provider>
);
}Context works in three moves:
- Create the context:
const ThemeContext = createContext()makes a shared channel. - Provide a value: wrap your components in
<ThemeContext.Provider value="dark">. Everything inside can now read that value. - Consume it anywhere below: inside
Toolbar,useContext(ThemeContext)reads the value ("dark") directly — no props passed throughApp.
Notice App did not pass a theme prop to Toolbar. Toolbar reached up and grabbed it from the provider itself. With deeply nested components, this saves you from threading the same prop through every layer.
Note: Output:
The heading App, and below it Current theme: dark — the word “dark” came from the provider, read directly by Toolbar.
Tip: Context is great for app-wide data: the current user, theme, language, or a shopping cart. For very large apps, dedicated state libraries (Redux, Zustand) build on the same idea.
Q. What problem does useContext mainly solve?
✍️ Practice
- Create a context for the current user and read it in a deep component.
- Use context to share a theme value across two components.
🏠 Homework
- Build a context that shares a language ("en"/"hi") and have two components display it.