AlgoInsight

Q&A

How to use the useContext hook in React

By AlgoInsight Team2026-06-18data-structuresfrontendreactreact-hooksjavascript

Overview

Context solves the "prop drilling" problem: passing data through many intermediary components just to reach a deep child. With context, you publish data at a high level and any descendant can read it directly. It's the go-to solution for theme, authentication, locale, and other app-wide state - though for frequently-changing state, external stores like Zustand may be better.

graph TD
    A["createContext(default)"] --> B["<Context.Provider value={...}>"]
    B --> C["Any descendant calls useContext(Context)"]
    C --> D["Gets the current value - no prop drilling"]
    B --> E["Value changes → all consumers re-render"]
    style C fill:#1e1b4b,color:#fff

Step 1: Create the Context

// ThemeContext.js
import { createContext } from "react";

export const ThemeContext = createContext("light");   // "light" = default value
// The default is used ONLY if a component renders outside any Provider

Step 2: Provide a Value

Wrap the subtree that needs access in a Provider and pass the current value:

// App.js
import { useState } from "react";
import { ThemeContext } from "./ThemeContext";
import Toolbar from "./Toolbar";

function App() {
  const [theme, setTheme] = useState("light");
  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      <Toolbar />
    </ThemeContext.Provider>
  );
}

Any component inside <ThemeContext.Provider> can now read { theme, setTheme }.

Step 3: Consume with useContext

// ThemedButton.js - deeply nested, no props needed
import { useContext } from "react";
import { ThemeContext } from "./ThemeContext";

function ThemedButton() {
  const { theme, setTheme } = useContext(ThemeContext);

  return (
    <button
      style={{ background: theme === "dark" ? "#333" : "#fff" }}
      onClick={() => setTheme(t => t === "dark" ? "light" : "dark")}
    >
      Toggle ({theme})
    </button>
  );
}

useContext returns whatever the nearest Provider's value is. When that value changes, ThemedButton re-renders.

Custom Hook Pattern (best practice)

Wrap useContext in a custom hook to hide the context detail and add error checking:

// useTheme.js
import { useContext } from "react";
import { ThemeContext } from "./ThemeContext";

export function useTheme() {
  const context = useContext(ThemeContext);
  if (!context) throw new Error("useTheme must be used within a ThemeProvider");
  return context;
}

// Usage anywhere:
const { theme, setTheme } = useTheme();

This is the idiomatic pattern - consumers never import ThemeContext directly, only useTheme.

Multiple Contexts

You can nest as many providers as needed:

<AuthContext.Provider value={authState}>
  <ThemeContext.Provider value={themeState}>
    <LocaleContext.Provider value={locale}>
      <App />
    </LocaleContext.Provider>
  </ThemeContext.Provider>
</AuthContext.Provider>

Each component calls useContext only for the context(s) it actually needs.

Performance Note: Re-renders on Every Value Change

Every consumer of a context re-renders whenever the Provider's value changes. If you pass an object/array directly as value, a new reference is created on every parent render, causing all consumers to re-render unnecessarily. Fix: useMemo the value, or split frequent-change and rare-change data into separate contexts.

// Memoize to prevent unnecessary re-renders:
const value = useMemo(() => ({ theme, setTheme }), [theme]);
<ThemeContext.Provider value={value}>

Context vs Global State Libraries

Context is ideal for low-frequency, app-wide values (auth user, theme, locale). For high-frequency state (many updates per second, large data trees) or complex update logic, external stores (Zustand, Redux, Jotai) are more efficient - they avoid re-rendering every consumer on every change.

Why This Matters in Interviews

React interviews use useContext to probe context mechanics and the prop-drilling solution. Key points: createContext → Provider → useContext chain; re-renders on value change; wrapping in a custom hook (the standard pattern); the re-render performance caveat with object values and useMemo as the fix; and when not to use context (high-frequency updates → global state library). Showing the custom-hook wrapper pattern signals idiomatic React.

Common Pitfalls

References

More answers