Last updated: Apr 29, 2026

Provider

The Provider Pattern uses React Context to wrap a subtree of components that need access to specific data. Child components opt in to that data via useContext instead of receiving it through props at every level. This avoids prop drilling and keeps intermediate components clean.

How It Works

  1. Create a context with createContext and give it a default value (or null).
  2. Wrap a subtree in a Provider component that holds the shared state and passes it through context.Provider.
  3. Consume the value in any descendant with useContext — no matter how deep.

Example

import { createContext, useContext, useState, type ReactNode } from "react";

type Theme = "light" | "dark";

interface ThemeContext {
  theme: Theme;
  toggle: () => void;
}

const ThemeCtx = createContext<ThemeContext | null>(null);

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

function ThemeProvider({ children }: { children: ReactNode }) {
  const [theme, setTheme] = useState<Theme>("light");
  const toggle = () => setTheme((t) => (t === "light" ? "dark" : "light"));

  return (
    <ThemeCtx.Provider value={{ theme, toggle }}>{children}</ThemeCtx.Provider>
  );
}

function Toolbar() {
  const { theme, toggle } = useTheme();
  return <button onClick={toggle}>Current: {theme}</button>;
}

function App() {
  return (
    <ThemeProvider>
      <Toolbar />
    </ThemeProvider>
  );
}

Toolbar reads the theme directly from context. Every component between ThemeProvider and Toolbar stays untouched — no forwarded props needed.

Trade-offs

ProsCons
Eliminates prop drilling through intermediate componentsHarder to trace where data comes from compared to explicit props
Clean consumer API — one useContext callEvery consumer re-renders when the context value changes, even if it only uses part of it
Provider is swappable (e.g. test vs production)Forgetting to memoize the value object causes unnecessary re-renders on every provider render