AtomLearnAtomLearn
DashboardGoalsPathAchievementsReviewSign In
DashboardReactuseContext
ReactNot Started

useContext

Share data across the component tree without prop drilling

0%
Knowledge0%
Learn & Drill
Fluency0%
Drill & Speed
Retention0%
Mastery & Review
Confidence0%
All modes
Practice

Free tier: read the explanation here. Upgrade to Pro for Drills, Speed challenges & Mastery badges.

Upgrade
Knowledge
Fluency
Retention

Knowledge Debt detected

You can study this freely — but your score may plateau if these foundations have gaps. The Mastery badge requires them to be solid.

Explanation

Context lets you pass data through the component tree without .

Create and provide context:

jsx import { createContext, useContext, useState } from 'react'; const ThemeContext = createContext('light'); // default value function App() { const [theme, setTheme] = useState('dark'); return ( <ThemeContext.Provider value={{ theme, setTheme }}> <MainLayout /> </ThemeContext.Provider> ); }

Consume context anywhere in the tree:

jsx function Navbar() { const { theme, setTheme } = useContext(ThemeContext); return ( <nav className={theme}> <button onClick={() => setTheme(t => t === 'dark' ? 'light' : 'dark')}> Toggle theme </button> </nav> ); }

When to use Context:

  • Theme (dark/light)
  • Current user / authentication
  • Language/locale
  • Global UI state (sidebar open/closed)

When NOT to use Context:

  • Frequently changing data (causes all consumers to re-render)
  • Data that isn't truly global (lift state instead)
  • As a full state management replacement — use Zustand, Redux, etc. for complex state

Context doesn't replace prop drilling for component libraries — explicit props are more debuggable.

Examples

Auth context pattern

Wrapping useContext in a custom hook is the standard pattern

const AuthContext = createContext(null);

export function AuthProvider({ children }) {
  const [user, setUser] = useState(null);

  const login = async (email, password) => {
    const u = await apiLogin(email, password);
    setUser(u);
  };

  const logout = () => setUser(null);

  return (
    <AuthContext.Provider value={{ user, login, logout }}>
      {children}
    </AuthContext.Provider>
  );
}

export const useAuth = () => useContext(AuthContext);

// Usage in any component:
function ProfileButton() {
  const { user, logout } = useAuth();
  return user ? <button onClick={logout}>{user.name}</button> : null;
}

Context with useReducer for complex state

useContext + useReducer is a lightweight Redux-like pattern for moderate complexity

const CartContext = createContext(null);

function cartReducer(state, action) {
  switch (action.type) {
    case 'ADD':    return [...state, action.item];
    case 'REMOVE': return state.filter(i => i.id !== action.id);
    default:       return state;
  }
}

export function CartProvider({ children }) {
  const [cart, dispatch] = useReducer(cartReducer, []);
  return (
    <CartContext.Provider value={{ cart, dispatch }}>
      {children}
    </CartContext.Provider>
  );
}

How well did you understand this?

Next in React

Custom Hooks

Continue