In short
You already know how Context works. The real question is when it's enough to run your app's state, and when it starts slowing your app down.
React's built-in mechanism for sharing client state (theme, auth status) across the component tree — a good fit for low-frequency updates without adding a library.

Think of it like this
The society WhatsApp group
Post one message about the water tanker and every phone in the building buzzes, even for people who don't care. Context works the same way: when its value changes, every component reading it re-renders, whether it needed to or not.
Watch it happen
One change, every reader re-renders
1/5AppContext holds { theme, cart }. ThemeToggle, ProductList and CartBadge all read it.
The big ideas
What you need to know
Good for slow-changing data
Theme, language, the logged-in user. Things that change rarely but are read in many places.
Pair it with useReducer
Put a reducer's state and dispatch in context and you get a mini Redux with no library at all.
Split by how often it changes
Keep fast-changing values, like a cart, in a separate context from slow ones, like the theme.
Know when to move on
If many components update often, or you want devtools and middleware, try Zustand or Redux Toolkit.
See it in code
Walk through the code
1import { createContext, useContext, useReducer, type Dispatch, type ReactNode } from "react";2 3type State = { items: string[] };4type Action = { type: "add"; item: string } | { type: "clear" };5 6function reducer(state: State, action: Action): State {7 if (action.type === "add") return { items: [...state.items, action.item] };8 return { items: [] };9}10 11const CartContext = createContext<{ state: State; dispatch: Dispatch<Action> } | null>(null);12export function CartProvider({ children }: { children: ReactNode }) {13 const [state, dispatch] = useReducer(reducer, { items: [] });14 return <CartContext value={{ state, dispatch }}>{children}</CartContext>;15}16export const useCart = () => useContext(CartContext)!;1/4The reducer works out the next cart from the current one and an action.
Any component inside CartProvider can call useCart() to read items or dispatch({ type: "add", item }). It's a small Redux-style store built only from React.
Save yourself the pain
Common mistakes
Oops
Putting user, theme, cart and notifications into one AppContext.
Do this instead
One change re-renders every reader. Split it up, so a new notification doesn't re-render the theme toggle.
Oops
Passing a brand-new value object from a provider that re-renders often.
Do this instead
Wrap the value in useMemo, or let the React Compiler handle it, so readers don't re-render for nothing.
Your mission
Count the re-renders
Quick check
A ThemeToggle reads AppContext, which holds { theme, cart }. You add an item to the cart. Does ThemeToggle re-render?
Go deeper
- 1Build a theme or auth context and consume it in a deeply nested component.
- 2Notice performance issues when a context value changes very frequently.
- 3Learn to split contexts by concern rather than one giant global context.
More topics at this stop
Stuck on this topic? Ask an Insider
Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.