Global state and performance
What "global state" is
Global state is data that different components from different parts of the application can access, for example:
- the current user,
- the theme (dark/light),
- authorization,
- the shopping cart,
- application settings, and so on.
This data is usually stored in:
- the React Context API (
useContext); - Redux / Zustand / Jotai / MobX;
- global store singletons.
The problem: excessive global state
When a developer starts putting everything into a global store, even things needed by only one component, a chain reaction of re-renders and added complexity appears in the application.
Why this hurts performance
1. Every global state update triggers mass re-renders
By default, React notifies every consumer of the context (or store) that reads it, even if it doesn't use the field that changed.
const ThemeContext = createContext();
function App() {
const [theme, setTheme] = useState('light');
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
<Header />
<Main />
<Footer />
</ThemeContext.Provider>
);
}If you change theme,
→ every component using useContext(ThemeContext)
gets re-rendered,
even if it doesn't display the theme directly.
The more components are tied to the context, the more unnecessary updates you get.
2. State loses its "locality"
If everything is stored in one big store, any update → triggers subscribers across the whole tree.
For example, changing the "search query" in a product list shouldn't touch the "user profile panel", but if everything is in one Redux slice, both get recomputed.
3. You can't memoize effectively
When data is global, it's hard to isolate a component:
const user = useSelector((state) => state.user);→ Any change in state.user triggers a re-render in React-Redux,
even if the component only uses user.name.
If there are dozens of such "small" subscriptions, a "cascade of re-renders" begins.
4. Contexts don't support partial updates
React Context does not support diffing by value.
If anything at all changes in the value,
every useContext consumer gets a new object → re-render.
<Provider value={{ theme, user }}>...</Provider>→ even if only user changed, a component that uses only theme
still re-renders, because the object { theme, user } is new by reference.
5. Cognitive load grows
The more global state there is, the harder it is to understand:
- what is stored where;
- who updates it;
- which components depend on what.
This leads to unpredictable side effects, and optimization becomes harder than the business logic itself.
6. Problems with concurrent rendering
In React 18, with concurrent mode enabled, React can:
- pause a render;
- roll back changes;
- re-render part of the tree.
A large global store makes this more expensive, because React is forced to copy and keep snapshots of a larger amount of data.
Example (illustrated)
// everything in a global context - a bad practice
const GlobalContext = createContext();
function App() {
const [theme, setTheme] = useState('light');
const [cart, setCart] = useState([]);
const [search, setSearch] = useState('');
const value = { theme, cart, search, setTheme, setCart, setSearch };
return (
<GlobalContext.Provider value={value}>
<Header /> // uses only theme
<Search /> // uses only search
<Cart /> // uses only cart
</GlobalContext.Provider>
);
}If you change search,
- Header and Cart still re-render,
because
value(the object) changed by reference.
Solutions (how to do it right)
1. Split your contexts / stores Create separate providers for independent parts:
<ThemeProvider>
<CartProvider>
<SearchProvider>
<App />
</SearchProvider>
</CartProvider>
</ThemeProvider>Each context updates in isolation.
2. Keep local state local
If the data is only needed by one component (or its children),
use useState directly in it, rather than in Redux/Context.
function SearchBar() {
const [query, setQuery] = useState('');
...
}3. Use selective subscriptions If you use Redux / Zustand, use selectors and shallow comparison to subscribe only to the fields you need.
const price = useSelector(state => state.cart.totalPrice);→ It will only change if totalPrice changes.
4. Use memoization and split components
- Wrap heavy components in
React.memo; - Pass handlers through
useCallback; - Split a component so that global data doesn't drag the whole tree along.
5. For complex state, use useContextSelector (or Jotai / Zustand)
React 19 will add Context Selectors natively.
For now you can use use-context-selector:
it lets you subscribe to a specific value in a context instead of the whole object.
Summary
| Reason | Why it's harmful |
|---|---|
| Mass re-renders | All subscribers update even for a small change |
| Poor isolation | Any change triggers the whole tree |
| Heavy snapshots | Increases memory use and GC work |
| Hard to understand dependencies | Increases the chance of bugs |
| No targeted optimization possible | Context doesn't diff by field |
The right mindset:
"Keep only what's necessary in global state. Keep everything else local, as close as possible to where it's used."
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.