ReactJS useContext Hook

As React applications grow, passing data from one component to another can become difficult. When data needs to travel through many component levels, code becomes cluttered and harder to maintain. This problem is commonly known as prop drilling.

The useContext Hook solves this issue by allowing components to access shared data directly, without passing props manually through every level.


What Is useContext?

useContext is a React Hook that allows a component to consume values from a Context.

In simple terms:

useContext lets a component read shared data from a central place.

Think of it Like This
  • Context → A central storage box
  • useContext → A key to open that box and read data
This shared data can include:
  • User information
  • Theme settings
  • Authentication status
  • Language preferences
  • Global configuration

Why Do We Need useContext?

The Problem: Prop Drilling

Prop drilling happens when:
  • A parent component has data
  • Many nested child components need that data
  • Props must be passed through components that don’t actually use it
Example (problematic pattern):

App → Layout → Sidebar → Profile → UserName

Even if only UserName needs the data, every component in between must pass it down.

This makes:
  • Components tightly coupled
  • Code harder to read
  • Refactoring more difficult

Recommended Folder Structure

This is a clean, industry-standard structure for Context usage.

useContext Folder Structure

Basic Steps to Use useContext

Using useContext always follows three basic steps:

Step 1: Create the Context File

Location: src/context/UserContext.js

What this file does
  • Creates the context
  • Exports it so other files can use it

import { createContext } from "react";

const UserContext = createContext(null);

export default UserContext;

That’s it, No hooks here, No components here, this file is only for creating context.


Step 2: Provide the Context (Initialization)

Location: src/App.js

What happens here:
  • You initialize the data
  • You wrap components with the Provider
  • This makes data available globally

import UserContext from "./context/UserContext";
import Dashboard from "./components/Dashboard";

function App() {
  const user = {
    name: "John",
    role: "Admin"
  };

  return (
    <UserContext.Provider value={user}>
      <Dashboard />
    </UserContext.Provider>
  );
}

export default App;

Important rules:
  • Provider must wrap all components that need access
  • value contains the shared data
  • Usually done in App.js

Step 3: Consume Context Using useContext

Location: src/components/Profile.js

This is where useContext is used:

import { useContext } from "react";
import UserContext from "../context/UserContext";

function Profile() {
  const user = useContext(UserContext);

  return (
    <div>
      <p>Name: {user.name}</p>
      <p>Role: {user.role}</p>
    </div>
  );
}

export default Profile;

What happens here:
  • useContext(UserContext) reads data
  • React finds the nearest Provider
  • user gets the value from App.js

When Should You Use useContext?

useContext is best when the same data is needed by many components at different levels of the component tree.

useContext use Cases
1. Authentication / Logged-in User Data
Scenario
  • User logs in once
  • Many components need user info:
    • Header (name)
    • Sidebar (role)
    • Dashboard (permissions)
    • Profile page
  • Why useContext
    • Avoid passing user through every component
    • Keeps authentication state centralized
2. Theme Management (Light / Dark Mode)
Scenario
  • User toggles theme
  • Entire app UI changes
  • Buttons, layouts, pages all depend on theme
Why useContext
  • Theme is global
  • Every component needs access
  • Changes should re-render UI automatically
3. Language / Localization (i18n)
Scenario
  • App supports multiple languages
  • Text across the app changes based on language
Why useContext
  • Language selection is global
  • Avoid passing language to every component
4. Global App Settings
Scenario
  • Currency (₹ / $)
  • Date format
  • Region-based settings
Why useContext
  • These values are shared
  • Rarely change
  • Required by many components
5. Shopping Cart (with useReducer)
Scenario
  • Add/remove products
  • Show cart count in header
  • Checkout page reads cart data
Why useContext
  • Cart is needed everywhere
  • Can be combined with useReducer for logic
6. Data Fetched Once, Used Everywhere
Scenario
  • Fetch user list once
  • Used by: Drop downs, tables, details page
Why useContext
  • Prevent repeated API calls
  • Share cached data

Final Summary

The useContext Hook allows React components to share data without prop drilling. It provides a clean and efficient way to manage global or shared state across the component tree. When used correctly, it simplifies architecture and improves code readability.

While useContext is powerful, it should be used thoughtfully. For complex state updates, combining useContext with useReducer offers a scalable and maintainable solution.