Clean β’ Professional
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.
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.
| Concept | Description |
|---|---|
| Context | A global object created using React.createContext() |
| Provider | A component that supplies data to the component tree |
| Consumer | Any component that uses the data from the Provider |
| useContext Hook | A 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.
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>
);
}
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:
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>
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>
);
}
The Context API is commonly used for:
useState, useReducer, or custom hooks.