← Back to Chapters

Context: Provider & Consumer

⚛️ Context: Provider & Consumer

? Quick Overview

Once you create a Context in React, you mainly work with two components: Provider and Consumer.

  • Provider — supplies (provides) the context value to its child components.
  • Consumer — reads (consumes) that value inside any component within the tree.
  • Any change in the Provider’s value automatically updates all Consumers using that context.

Together, Provider and Consumer help you implement global state without prop-drilling.

? Key Concepts

  • Context Object — created using createContext().
  • Provider Component — wraps part of the component tree and passes a value.
  • Consumer Component — subscribes to the Provider and receives that value.
  • Render Props Pattern — used by Consumer to get the value via a function.
  • Modern AlternativeuseContext() hook replaces most Consumer use cases.

? Provider Component

The Provider component is used to supply data to all components within its scope. Any component nested inside the Provider can access the value it passes.

? Step 1: Create the Context

? View Code Example (ThemeContext.js)
// ThemeContext: creates a context with "light" as default theme
import React, { createContext } from "react";

const ThemeContext = createContext("light");

export default ThemeContext;

? Step 2: Provide the Value (App.js)

? View Code Example (App.js with Provider)
// App component: wraps children with ThemeContext.Provider
import React, { 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>
  );
}

export default App;

? Explanation

  • ThemeContext.Provider wraps <Toolbar />.
  • The value prop passes both theme and setTheme to all children.
  • Any component below the Provider can now read and update the theme via the context.

You can also nest multiple Providers like AuthProvider, ThemeProvider, etc., to manage different global states separately.

? Tip: Place Providers as high as necessary (often near <App />) so that more components can access the shared data.

? Consumer Component (Traditional Method)

The Consumer component is an older approach used before React Hooks were introduced. It uses the render props pattern to access the context value.

? View Code Example (Toolbar.js with Consumer)
// Toolbar: consumes ThemeContext using the Consumer component
import React from "react";
import ThemeContext from "./ThemeContext";

function Toolbar() {
  return (
    <ThemeContext.Consumer>
      {({ theme, setTheme }) => (
        <div
          className={`p-3 text-center bg-${
            theme === "light" ? "light" : "dark"
          } text-${theme === "light" ? "dark" : "light"}`}
        >
          <p>Current Theme: {theme}</p>
          <button
            className="btn btn-primary"
            onClick={() => setTheme(theme === "light" ? "dark" : "light")}
          >
            Toggle Theme
          </button>
        </div>
      )}
    </ThemeContext.Consumer>
  );
}

export default Toolbar;

? How Consumer Works

  • <ThemeContext.Consumer> expects a function as its child.
  • React calls that function and passes the context value — here, {`{ theme, setTheme }`}.
  • The UI uses theme to set classes and setTheme to toggle between modes.

This pattern was common before useContext() made reading context much simpler in function components.

⚙️ Provider & Consumer Flow

  1. Provider: Wraps components and provides a context value.
  2. Consumer: Reads and uses that value inside any subscribed component.
  3. When the Provider’s value changes, all Consumers automatically re-render.
? View Code Example (Conceptual Flow)
// Conceptual flow of data in React Context
Provider (value) → supplies context
↓
Consumer / useContext() → reads context
↓
UI → updates automatically when value changes

? Multiple Consumers Example

You can use more than one Consumer inside the same component when multiple contexts are involved (for example, theme + authentication).

? View Code Example (Multiple Context Consumers)
// Example: reading both ThemeContext and AuthContext
<ThemeContext.Consumer>
  {({ theme }) => (
    <AuthContext.Consumer>
      {({ user }) => (
        <p>
          {user ? `${user.name}'s Theme is ${theme}` : "Guest"}
        </p>
      )}
    </AuthContext.Consumer>
  )}
</ThemeContext.Consumer>
? Tip: When using multiple contexts, the useContext() hook is cleaner and avoids deeply nested Consumers, making the code more readable.

? Provider vs Consumer

Feature Provider Consumer
Purpose Supplies context value Consumes context value
Usage Wraps components Used inside components
API Type JSX Element Render Props (pre-Hooks)
Modern Alternative Same usage useContext() Hook

?️ Live Output / What User Sees

? Simulated UI Behavior

Initial state: Theme is "light".

  • The background appears as a light theme.
  • Text shows: Current Theme: light.
  • Button label: Toggle Theme.

After clicking the button:

  • setTheme switches the value to "dark".
  • All Consumers re-render and now show a dark theme.
  • Text updates to: Current Theme: dark.

No props were passed manually through intermediate components — everything flowed via Context.

? Tips & Best Practices

  • Wrap Providers as high as needed (often around <App />).
  • Use descriptive names like AuthContext, ThemeContext, or UserContext.
  • Avoid deeply nesting Consumers; prefer useContext() wherever possible.
  • Keep context values small and focused (e.g., only what needs to be global).
  • Move heavy logic outside of Context when possible to avoid unnecessary re-renders.

? Try It Yourself

  1. Create a UserContext with default name "Guest".
  2. Wrap your App in UserContext.Provider and pass a name value.
  3. Use UserContext.Consumer in another component to display "Welcome, <name>!".
? View Code Example (Practice Idea)
// Practice: simple UserContext with Provider and Consumer
const UserContext = createContext("Guest");

function App() {
  return (
    <UserContext.Provider value="Meghraj">
      <WelcomeBanner />
    </UserContext.Provider>
  );
}

function WelcomeBanner() {
  return (
    <UserContext.Consumer>
      {(name) => <h2>Welcome, {name}!</h2>}
    </UserContext.Consumer>
  );
}

Goal: Understand how Provider and Consumer together enable global data flow in React apps without prop-drilling.