HooksIntermediate6 min11 / 12

The useContext Hook

Share data across a whole component tree without threading props through every level — the fix for prop-drilling.

When a value (the theme, the current user, a language) is needed by many components at different depths, passing it down as props through every layer — prop-drilling — gets painful. Context lets a parent broadcast a value to any descendant that asks for it.

#Three steps

create · provide · consume
import { createContext, useContext, useState } from 'react';

// 1. create the context
const ThemeContext = createContext('light');

function App() {
  const [theme, setTheme] = useState('dark');
  // 2. provide a value to the subtree
  return (
    <ThemeContext.Provider value={theme}>
      <Toolbar />
    </ThemeContext.Provider>
  );
}

function Toolbar() { return <ThemedButton />; }

function ThemedButton() {
  // 3. consume it — no props needed, at any depth
  const theme = useContext(ThemeContext);
  return <button className={theme}>I'm {theme}</button>;
}

ThemedButton reads theme directly with useContext, even though Toolbar never received or passed it. Any component inside the Provider can grab the value.

Common mistake

Context isn't a state manager

Context handles distribution, not storage. You still hold the value in useState/useReducer and pass it (and its setters) as the Provider's value. Also, every consumer re-renders when the Provider's value changes — so don't put rapidly-changing, unrelated values in one big context.

Quick check

What problem does Context primarily solve?

Key takeaways

  • Context shares a value with a whole subtree without prop-drilling.
  • Three steps: createContext, wrap with <Context.Provider value={...}>, read with useContext.
  • Any descendant inside the Provider can consume the value at any depth.
  • Context distributes data; you still store it in state. Consumers re-render when the value changes.
Practice challenges
Test yourself · earn XP
0/3
Fix the bug#1

useContext returns the default 'light', ignoring the value the app set. Why?

fix-bug
const ThemeContext = createContext('light');
function App() {
  return <Toolbar />; // no Provider!
}
function Btn() { return <b>{useContext(ThemeContext)}</b>; }
Reorder the lines#2

Order the three steps to use Context.

1
Read it in any descendant: const theme = useContext(ThemeContext)
2
Wrap the subtree: <ThemeContext.Provider value={theme}>…</ThemeContext.Provider>
3
const ThemeContext = createContext(defaultValue)
Predict the output#3

What does Context primarily let you avoid?

predict-output
// theme needed by a deeply nested button
Your turn
Practice exercise

You have a user object in <App> that a deeply nested <Avatar> needs. Outline how to deliver it with Context instead of passing user through every component in between.

Try it live — edit the code and hit Run to see it rendered:

solution.jsx · editable