R

React Handbook

Clean • Professional

React Context API: Manage Global State with Provider & Consumer

3 minute

React Context API

In large React applications, passing data through multiple component levels (known as prop drilling) can become messy and difficult to maintain.

To solve this, React provides a built-in feature called the Context API — a powerful tool for managing global state and sharing data across components without having to manually pass props at every level.

What is the React Context API?

The Context API allows you to create global variables or data that can be accessed by any component in your app — no matter how deeply nested it is in the component tree.

You can think of it as a “shared data store” within React, where components can both provide and consume values.

Key Concepts:

ConceptDescription
ContextA global object created using React.createContext()
ProviderA component that supplies data to the component tree
ConsumerAny component that uses the data from the Provider
useContext HookA simpler way to access context values without wrapping components in a Consumer

Syntax:

const MyContext = React.createContext(defaultValue);

This creates a new Context object.

You’ll then use the Provider and Consumer components to share and access the data.

Creating and Providing Context

The Provider component wraps parts of your app and passes down values through the value prop.

import React, { createContext, useState } from "react";

const UserContext = createContext(); // Create context

function App() {
  const [user, setUser] = useState("Alice");

  return (
    <UserContext.Provider value={{ user, setUser }}>
      <Toolbar />
    </UserContext.Provider>
  );
}

function Toolbar() {
  return (
    <div>
      <UserProfile />
    </div>
  );
}

Consuming Context Data

There are two ways to consume context data:

A. Using useContext (Recommended)

import React, { useContext } from "react";
import { UserContext } from "./App";

function UserProfile() {
  const { user, setUser } = useContext(UserContext);

  return (
    <div>
      <h2>Logged in as: {user}</h2>
      <button onClick={() => setUser("Bob")}>Switch User</button>
    </div>
  );
}

Benefits of useContext:

  • Cleaner and easier than the traditional Consumer pattern
  • No nested render functions
  • Updates automatically when context value changes

B. Using Context.Consumer (Older Pattern)

Before hooks, React used the Consumer pattern to access context data.

<UserContext.Consumer>
  {({ user, setUser }) => (
    <div>
      <h2>Welcome, {user}!</h2>
      <button onClick={() => setUser("Charlie")}>Change User</button>
    </div>
  )}
</UserContext.Consumer>

Updating Global State with Context

Context isn’t just for static values — you can store and update dynamic state as well.

By combining useState (or even useReducer) with Context, you can create global state managers.

Example:

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

const ThemeContext = createContext();

export function ThemeProvider({ children }) {
  const [theme, setTheme] = useState("light");

  const toggleTheme = () => {
    setTheme((prev) => (prev === "light" ? "dark" : "light"));
  };

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

export function ThemeButton() {
  const { theme, toggleTheme } = useContext(ThemeContext);

  return (
    <buttononClick={toggleTheme}
      style={{
        background: theme === "dark" ? "#333" : "#fff",
        color: theme === "dark" ? "#fff" : "#000",
      }}
    >
      Toggle Theme (Current: {theme})
    </button>
  );
}

Usage:

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

Real-World Use Cases

The Context API is commonly used for:

  • Theme Management (light/dark mode)
  • User Authentication (login, logout, user details)
  • Language/Localization
  • Global Settings or Configurations
  • Shopping Cart or App-wide Data

Benefits of Using Context API

  • Eliminates Prop Drilling – No need to manually pass props through every component.
  • Simplifies Global State – Manage shared data easily.
  • Improves Readability – Clean, declarative structure.
  • Works with Hooks – Combine with useState, useReducer, or custom hooks.
  • Lightweight Alternative to Redux – Ideal for small to medium apps.

Article 0 of 0