Prop drilling
The signed-in user is needed by the header, a sidebar and a button five levels deep. Passing it through every component in between is called *prop drilling*. context lets any component below a provider read a value directly.
createContext, Provider, useContext
import { createContext, useContext, useState } from "react";
const ThemeContext = createContext("light");
function Button({ children }) {
const theme = useContext(ThemeContext);
const style = theme === "dark" ? { background: "#222", color: "#fff" } : {};
return <button style={style}>{children}</button>;
}
function Toolbar() {
return <div><Button>Save</Button> <Button>Share</Button></div>;
}
export default function App() {
const [theme, setTheme] = useState("light");
return (
<ThemeContext.Provider value={theme}>
<Toolbar />
<label>
<input type="checkbox" onChange={(e) => setTheme(e.target.checked ? "dark" : "light")} /> Dark
</label>
</ThemeContext.Provider>
);
}- Good uses: current user, theme, language, a shopping cart.
- Don't reach for context first — passing props a level or two is clearer.
- Common pattern: a provider component that holds state and exposes { value, actions }, plus a useCart() custom hook that calls useContext.
- Since React 19 you can also render <ThemeContext value={theme}> directly; .Provider still works, but React plans to deprecate it.