What you'll learn
- Context for low-frequency shared values
- Zustand when many consumers need frequent, selective updates
- Code shapes for both
- A decision table and mistakes to avoid
Direct answer: use Context for values that change rarely and are read by a subtree (theme, locale, current user id). Use Zustand (or a similar store) when many unrelated components subscribe to different slices that update often.
Both can share state across the tree. They differ in how updates notify readers.
When to use Context
- Theme, locale, auth user identity
- Dependency injection for a feature subtree
- Values that change on navigation or user preference, not every keystroke
When to use Zustand
- Dashboard filters, selections, or UI chrome shared across distant screens
- High-frequency updates where Context would re-render large subtrees
- You want selectors so each component reads only what it needs
When not to use either
- Isolated form inputs: local state
- Server lists and caches: server-state library (see State Management)
Practical examples
Context (fine for rare updates):
JSX
const ThemeContext = React.createContext('light')
function App() {
const [theme, setTheme] = React.useState('light')
return (
<ThemeContext.Provider value={theme}>
<Toolbar onToggle={() => setTheme((t) => (t === 'light' ? 'dark' : 'light'))} />
<Page />
</ThemeContext.Provider>
)
}Zustand (selective subscriptions):
JavaScript
import { create } from 'zustand'
const useUi = create((set) => ({
sidebarOpen: true,
setSidebarOpen: (sidebarOpen) => set({ sidebarOpen }),
}))
function SidebarToggle() {
const open = useUi((s) => s.sidebarOpen)
const setOpen = useUi((s) => s.setSidebarOpen)
return <button onClick={() => setOpen(!open)}>{open ? 'Close' : 'Open'}</button>
}Comparison
| Need | Context | Zustand |
|---|---|---|
| Built into React | Yes | Library |
| Default update scope | All consumers of that value | Selectors per field |
| Best for | Rare shared config | Frequent shared UI/app state |
| Risk | Accidental wide re-renders | Extra dependency and store sprawl |
Common mistakes
- One mega Context object that changes every render
- Zustand for every tiny bit of local UI state
- Putting server cache into Zustand without a fetch library
Checklist
- Does the value change rarely? Prefer Context.
- Do distant screens need frequent selective updates? Prefer a store.
- Can local or lifted state solve it? Prefer that first.
- Split Context by update rate if you keep Context.
Related
Final recommendation
Start with local and lifted state. Add Context for slow-changing shared config. Reach for Zustand when Context re-renders become a measured problem or selectors clearly help.