How to create global state with useContext?
What useContext does
useContext lets you:
Create a "global container" of data (via
Context) Give any component in the tree access to that data Without passing props "down the chain" (prop drilling)
1. Create a context
import { createContext } from "react";
// Create the context
export const ThemeContext = createContext();A context is a "box" in which React will store data. Later you'll "pour" state into it and "spread" it across the app.
2. Create a provider (the component that holds the state)
import { useState, createContext } from "react";
// create the context
export 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>
);
}What happens here:
- We created a global
themestate - We wrapped it in
<ThemeContext.Provider /> - We passed into
valuewhat we want to share (theme,toggleTheme)
Now every child component inside <ThemeProvider> can access this data.
3. Wrap the whole app in the provider
In App.jsx or main.jsx:
import { ThemeProvider } from "./ThemeContext";
import Page from "./Page";
function App() {
return (
<ThemeProvider>
<Page />
</ThemeProvider>
);
}
export default App;Now every component inside ThemeProvider
can use useContext(ThemeContext)
and read / change the global state.
4. Use useContext in any component
import { useContext } from "react";
import { ThemeContext } from "./ThemeContext";
function Header() {
const { theme, toggleTheme } = useContext(ThemeContext);
return (
<header
style={{
backgroundColor: theme === "light" ? "#fff" : "#333",
color: theme === "light" ? "#000" : "#fff",
}}
>
<p>Current theme: {theme}</p>
<button onClick={toggleTheme}>Toggle theme</button>
</header>
);
}That's it!
The Header component now has access to the global theme state,
even though it's stored "at the top" of the app, without passing it through props.
How it works under the hood
createContext()creates a "communication channel" between components.<Provider value={...}>makes the data available to all descendants.useContext(Context)subscribes the component to updates of that context. → Ifvaluein the provider changes, React re-renders all subscribers.
Important: useContext is not a silver bullet
Although Context = "global state", you need to use it carefully:
| Problem | Description |
|---|---|
| All subscribers re-render | On every change of the value in Provider |
| Not suited for very frequently changing data | For example, an FPS counter or mouse position |
| Better suited for "settings" | Theme, language, current user, auth |
For frequently updated data it's better to use Zustand, Jotai, Redux, or to split contexts (so each one holds only one part of the state).
Full project structure example
src/
├─ context/
│ └─ ThemeContext.jsx
├─ components/
│ ├─ Header.jsx
│ └─ Footer.jsx
├─ App.jsx
└─ main.jsxThemeContext.jsx
import { createContext, useState } from "react";
export 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>
);
}Header.jsx
import { useContext } from "react";
import { ThemeContext } from "../context/ThemeContext";
export function Header() {
const { theme, toggleTheme } = useContext(ThemeContext);
return (
<header className={theme}>
<h1>Theme: {theme}</h1>
<button onClick={toggleTheme}>Toggle</button>
</header>
);
}App.jsx
import { ThemeProvider } from "./context/ThemeContext";
import { Header } from "./components/Header";
export default function App() {
return (
<ThemeProvider>
<Header />
</ThemeProvider>
);
}Summary
| Question | Answer |
|---|---|
What does useContext do? | Lets you read data from the closest <Context.Provider> |
| How to create global state? | Wrap the state in a Context.Provider and use useContext |
| When to use it? | When data is needed in different places in the tree (theme, language, user) |
| What to replace it with in complex cases? | Zustand, Redux, Jotai, Recoil, etc. |
| How to avoid extra re-renders? | Split contexts and memoize value (via useMemo) |
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.