Skip to main content

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

javascript
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)

javascript
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 theme state
  • We wrapped it in <ThemeContext.Provider />
  • We passed into value what 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:

javascript
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

javascript
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

  1. createContext() creates a "communication channel" between components.
  2. <Provider value={...}> makes the data available to all descendants.
  3. useContext(Context) subscribes the component to updates of that context. → If value in 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:

ProblemDescription
All subscribers re-renderOn every change of the value in Provider
Not suited for very frequently changing dataFor 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

javascript
src/ ├─ context/ │ └─ ThemeContext.jsx ├─ components/ │ ├─ Header.jsx │ └─ Footer.jsx ├─ App.jsx └─ main.jsx

ThemeContext.jsx

javascript
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

javascript
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

javascript
import { ThemeProvider } from "./context/ThemeContext"; import { Header } from "./components/Header"; export default function App() { return ( <ThemeProvider> <Header /> </ThemeProvider> ); }

Summary

QuestionAnswer
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 ready
Premium

A concise answer to help you respond confidently on this topic during an interview.