Sitemap

Context API (State Management Intro)

3 min readMar 16, 2026

--

As React apps grow, managing shared state becomes harder. Passing data through multiple layers of components can get messy.

This is where the Context API helps.

The Core Problem: Prop Drilling

Imagine this component structure:

App
└── Layout
└── Sidebar
└── UserProfile

Now, suppose App has user data, and UserProfile needs it.:

const user = { name: "John" };

Without Context, you must pass it down like this, even if Layout and Sidebar don’t use user.:

<App user={user}>
<Layout user={user}>
<Sidebar user={user}>
<UserProfile user={user} />
</Sidebar>
</Layout>
</App>

This is called Prop Drilling: passing the same data through many layers of components that don’t actually need it.

Why is this bad?

  • Components receive props they don’t use
  • Code becomes hard to maintain
  • Deep trees become messy
  • Refactoring becomes painful

Context

Context allows you to share data globally without passing props manually at every level.

It’s built-in state management for small-to-medium React apps.

To use Context, you need three specific parts: Create the Context, Provide the Context, and Consume the Context.

  1. Create the Context

This is the “container” for your data.

import { createContext } from "react";

// Create context
export const UserContext = createContext();

This creates a data channel.

Get Nimmikrishnab’s stories in your inbox

Join Medium for free to get updates from this writer.

2. Provide the Context

Wrap the part of your component tree that needs the data in a Provider. The Provider makes data available to all components inside it.

import { UserContext } from "./UserContext";

function App() {
const user = { name: "Harry" };

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

3. Consume the context (useContext)

Inside a child component, use the useContext hook to grab the data.

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

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

return <h2>{user.name}</h2>;
}
// No props passed through intermediate components.
// without context
App → Layout → Sidebar → UserProfile
(props passed manually each level)

// with context
App (Provider)
↓
All nested components can access data directly

Updating Context State

Context isn’t just for static data. You can pass an object containing both the state and the updater function into the value prop.

// In the Provider
const value = {
user,
logout: () => setUser(null)
};

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

When to Use Context (and When Not To)

While Context is powerful, it shouldn’t be your default for everything.

  • Good for: “Global” data like Themes (Dark/Light mode), User authentication, Language settings (i18n), or simple Shopping Carts.
  • Bad for: Highly frequent updates (like a text input or a game loop). When a Context value changes, every component consuming that context re-renders, which can lead to performance lag.

Context vs. Redux/Zustand (popular state management libraries)

  • Context API: Best for low-frequency updates and smaller apps. It’s built into React, so there is no extra bundle size.
  • Redux/Zustand: Better for complex logic, high-performance needs, and “undo/redo” features. They offer better debugging tools (DevTools).

Summary

Context API lets you share state globally without manually passing props down the component tree.

  • Create the context using createContext().
  • Wrap the parent in <Context.Provider value={...}>.
  • Access the data in any child using useContext(Context).
  • Use it sparingly to avoid unnecessary re-renders.

--

--