← Back to the Build Your Homepage series
⚛️
EPISODE 03
Prop drilling · Context.Provider · custom provider

useContext

Stop drilling props through layers. Use Context to share theme, auth, or i18n state — wrapped in a clean custom provider component.

ContextuseContextProviderglobal state
Duration
About 1.5 hours
Level
📊 Intermediate
Prerequisite
🎯 react-02
OUTCOME
A theme/auth context shared across an app without prop drilling

What you'll learn

  • 1Create a Context with a default value
  • 2Build a custom Provider component
  • 3Consume the context with useContext
  • 4Know when NOT to use Context (frequent updates)

1. Create the Context

tsx
import { createContext, useContext, useState } from "react";

type Theme = "light" | "dark";
const ThemeContext = createContext<{
  theme: Theme;
  toggle: () => void;
} | null>(null);

export function ThemeProvider({ children }: { children: React.ReactNode }) {
  const [theme, setTheme] = useState<Theme>("light");
  const toggle = () => setTheme(t => t === "light" ? "dark" : "light");
  return (
    <ThemeContext.Provider value={{ theme, toggle }}>
      {children}
    </ThemeContext.Provider>
  );
}

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

2. Provide and Consume

tsx
// app/layout.tsx
<ThemeProvider>
  <App />
</ThemeProvider>

// Anywhere in the tree
function Header() {
  const { theme, toggle } = useTheme();
  return <button onClick={toggle}>Theme: {theme}</button>;
}

3. Context Gotchas

  • Every consumer re-renders when the context value changes
  • Split fast-changing state into a separate context (or use a state library)
  • Memoize the provider value with useMemo when it contains objects
Example code / lecture materials

All lecture materials and example code are openly available on GitHub.

View on GitHub ↗