Skip to main content

Why isn't Context always suitable for global state?

The key idea

React Context is not the same as a global store, it is designed as a mechanism for passing data down the tree without prop drilling, not as a full-fledged state-management system.


Why Context is not always suitable for global state

1. Every change to value re-renders all consumers

When you write:

javascript
<MyContext.Provider value={{ user, theme }}> <App /> </MyContext.Provider>

React compares value by reference. If it has changed -> every component using useContext(MyContext) re-renders, even if the field it needs did not change.

On a large tree, this causes cascading updates and lag.

Example: user.name changes -> the whole UI using theme re-renders too.


2. There are no "selectors" (granular subscriptions)

Context cannot subscribe a component to only part of the data.

If value holds { user, theme, cart }, then a change to cart updates even the components that only need theme.

The workaround is to use third-party tools (use-context-selector, Zustand, Jotai), but "plain" Context does not provide this.


3. Every update goes through a React render

Context is not optimized for frequently changing state (for example, a cursor, a timer, text input). At 60 updates per second, React simply cannot keep up.

Context is UI state, not a "reactive stream".


4. There are no tools, middleware, or devtools

Context:

  • has no devtools;
  • does not support time-travel;
  • does not make it convenient to log changes, roll back state, or debug business logic;
  • does not scale with a complex architecture.

5. Hard to scale as the app grows

As the app grows, "crutches" start appearing: dozens of contexts (AuthContext, CartContext, UIContext, SettingsContext...), nested Provider trees, tangled dependencies, and "Provider hell":

javascript
<AuthProvider> <ThemeProvider> <UIProvider> <CartProvider> <App /> </CartProvider> </UIProvider> </ThemeProvider> </AuthProvider>

Hard to maintain, test, and extend.


6. Context is synchronous and local

It is not designed for:

  • asynchronous requests (fetch/cache/retry);
  • syncing with a server;
  • offline data;
  • reactive subscriptions (WebSocket, SSE, etc.).

For that, React Query, Zustand, Redux Toolkit, and others are a better fit.


When Context is still ideal

Use caseWhy it fits
Theme (light/dark)Simple, rare change
Interface language (i18n)Updates only when the language is switched
Current userChanges only on login/logout
Feature flags, settingsSmall amount of data, low change frequency
Compound componentsContext is used as an internal communication bus (Tabs, Modal, Dropdown, etc.)

Alternatives for "real" global state

TaskTool
Frequently changing state, business logicZustand, Jotai, Redux Toolkit
Asynchronous data (fetch, cache)TanStack Query (React Query)
Reactive subscriptions, server pushesRxJS, useSyncExternalStore, a custom store
Simple static dataContext

Summary

ReasonWhy Context does not fit
Frequent updatesAll consumers re-render
No selectorsYou cannot subscribe to just part of the data
No toolingYou cannot debug or control the flow
Poor scalabilityProvider hell and complex dependencies
No asynchronyEverything is synchronous and local

Conclusion:

Context is a mechanism for "passing data down the tree", not a "global state store".

For small global flags, it's great. For complex business state, Zustand, Jotai, Redux Toolkit, or React Query are better.

Short Answer

Interview ready
Premium

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