React - Context API

In React, data normally flows from parent to child. When a deeply nested component needs some data, that data must be passed through every intermediate component, even if those components do not use it. This is known as data or prop drilling, and it makes code harder to read, maintain and scale. Managing shared data across components is a common challenge in React applications. As your app grows, passing data through multiple component layers becomes inefficient and difficult to maintain. To solve this problem, React provides a powerful built-in feature called the Context API.

The Context API eliminates this problem by providing a central place to store shared data. A context is created using createContext(), and the data is supplied to the component tree using a Provider. Any child component inside this Provider can access the data directly using the useContext() hook, without relying on props.

As a result, intermediate components no longer need to receive or forward unnecessary props. This leads to cleaner component interfaces, improved readability, and easier maintenance. Context API is commonly used for global data such as authentication details, themes, language preferences, and UI state. However, it should be used carefully, as frequent updates can trigger unnecessary re-renders.

1. What Is Context API in React?

 
The Context API is a React feature that allows you to share data globally across components without passing props manually at every level.
 
Context provides a way to pass data through the component tree without having to pass props down manually at every level.
 
It is commonly used for:
  • Theme management (dark / light mode)
  • Authentication data
  • User preferences
  • Language selection
  • Global UI state
 
What Is Prop Drilling?
 
Prop drilling occurs when data must be passed through multiple intermediate components that don’t actually need it.
 
For example – Component Structure
 
App
 └── Dashboard
      └── Profile
           └── UserDetails
 
Without Context (Prop Drilling)
 
App (user)
 └── Dashboard (user)
      └── Profile (user)
           └── UserDetails (user)
 
Every component receives the ‘user’ prop—even though only ‘UserDetails’ uses it.
 
Problems with Prop Drilling
 
  • Unnecessary props
  • Poor readability
  • Hard to maintain
  • Reduced component reusability
  
How Context API Solves This Problem
 
With Context API:
 
UserContext
   ↓
App
 └── Dashboard
      └── Profile
           └── UserDetails (consumes context)
 
Now 
  • No intermediate props
  • Clean component hierarchy
  • Direct access to shared data
 

2. Core Concepts of Context API

 
Context API has three main parts:
 
1. ‘createContext()’ – Creates context
2. ‘Provider’ – Supplies data
3. ‘useContext()’ – Consumes data
 
 
Step-by-Step Context API Example
 
Step 1: Create Context
 
import { createContext } from “react”;
 
const UserContext = createContext();
 
export default UserContext;
 
In this step, we create a context object using React’s createContext() function. 
UserContext acts as a container for shared data. At this stage, no data is stored yet. 
It simply defines what type of data can be shared across components
 
 
Step 2: Provide Context
 
import UserContext from “./UserContext”;
import Dashboard from “./Dashboard”;
 
function App() {
  const user = { name: “Pat”, role: “React Developer” };
 
  return (
    <UserContext.Provider value={user}>
      <Dashboard />
    </UserContext.Provider>
  );
}
 
export default App;
 
Here, we use the Context Provider to supply data.UserContext.Provider makes the user object available. The value prop holds the data to be shared. Every component inside <Dashboard /> can now access this data. This eliminates the need to pass user as props through multiple components.
 
 
 
Step 3: Consume Context Using `useContext`
 
import { useContext } from “react”;
import UserContext from “./UserContext”;
 
function UserDetails() {
  const user = useContext(UserContext);
 
  return (
    <div>
      <p>Name: {user.name}</p>
      <p>Role: {user.role}</p>
    </div>
  );
}
 
export default UserDetails;
 
In this step, we consume the context data. useContext(UserContext) directly accesses the shared data. No props are required. The component automatically updates if the context value changes.
 
 

3. Project: Theme Switcher Using Context API

 
Let’s build a Dark / Light Theme Switcher using Context API.
 
Project Structure
 
src/
 ├── ThemeContext.js
 ├── ThemeProvider.js
 ├── ThemeButton.js
 ├── App.js
 
 
1. Create Theme Context
 
ThemeContext.js
 
import { createContext } from “react”;
const ThemeContext = createContext();
export default ThemeContext;
 
 
2. Create Theme Provider
 
ThemeProvider.js
 
import { useState } from “react”;
import ThemeContext from “./ThemeContext”;

 

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

 

  const toggleTheme = () => {
    setTheme((prevTheme) =>
      prevTheme === “light” ? “dark” : “light”
    );
  };

 

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

 

export default ThemeProvider;

 

 
 
3. Consume Context
 
ThemeButton.js
 
import { useContext } from “react”;
import ThemeContext from “./ThemeContext”;

 

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

 

  return (
    <div
      style={{
        backgroundColor: theme === “light” ? “#ffffff” : “#222222”,
        color: theme === “light” ? “#000000” : “#ffffff”,
        minHeight: “100vh”,
        padding: “40px”
      }}
    >
      <h2>Current Theme: {theme}</h2>
      <button onClick={toggleTheme}>
        Toggle Theme
      </button>
    </div>
  );
}

 

export default ThemeButton;

 

 
 
4. Wrap App with Provider
 
App.js
 
import ThemeProvider from “./ThemeProvider”;
import ThemeButton from “./ThemeButton”;

 

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

 

export default App;

 

 
 
Scroll to Top