When props need to travel through many component layers, Context provides a clean way to share data without prop-drilling.
1// ❌ Passing theme 5 levels deep just to reach a Button
2<App theme="dark">
3 <Layout theme="dark">
4 <Sidebar theme="dark">
5 <NavItem theme="dark">
6 <Button theme="dark" />
7 </NavItem>
8 </Sidebar>
9 </Layout>
10</App>1import { createContext, useContext, useState } from "react";
2
3// 1. Create the context
4const ThemeContext = createContext("light");
5
6// 2. Provide the value at the top level
7function App() {
8 const [theme, setTheme] = useState("dark");
9 return (
10 <ThemeContext.Provider value={{ theme, setTheme }}>
11 <Layout />
12 </ThemeContext.Provider>
13 );
14}
15
16// 3. Consume anywhere in the tree — no props needed!
17function Button() {
18 const { theme } = useContext(ThemeContext);
19 return <button className={`btn btn-${theme}`}>Click me</button>;
20}✅ Use Context for:
❌ Don't use Context for:
1// auth-context.jsx
2const AuthContext = createContext(null);
3
4export function AuthProvider({ children }) {
5 const [user, setUser] = useState(null);
6
7 const login = (userData) => setUser(userData);
8 const logout = () => setUser(null);
9
10 return (
11 <AuthContext.Provider value={{ user, login, logout }}>
12 {children}
13 </AuthContext.Provider>
14 );
15}
16
17// Custom hook — cleaner API for consumers
18export function useAuth() {
19 const ctx = useContext(AuthContext);
20 if (!ctx) throw new Error("useAuth must be inside AuthProvider");
21 return ctx;
22}Now any component can call const { user, login } = useAuth(); directly.