Choosing the right state management is one of the most impactful architectural decisions. Here's my honest comparison after using all three at Google.
React Context
Built-in, zero dependencies. But it has a major limitation: any value change re-renders ALL consumers.
const ThemeContext = createContext();
function ThemeProvider({ children }) {
const [theme, setTheme] = useState("light");
// Every consumer re-renders when theme changes,
// even if they only use setTheme
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
);
}
// Mitigation: split contexts
const ThemeValueContext = createContext();
const ThemeSetterContext = createContext();Zustand
My recommendation for most apps. Minimal boilerplate, great performance, tiny bundle (1KB).
import { create } from "zustand";
const useStore = create((set, get) => ({
bears: 0,
fish: 0,
addBear: () => set(state => ({ bears: state.bears + 1 })),
addFish: () => set(state => ({ fish: state.fish + 1 })),
// Derived state
get total() { return get().bears + get().fish; }
}));
// Components only re-render when their selected state changes
function BearCount() {
const bears = useStore(state => state.bears);
return <span>{bears}</span>;
}Redux Toolkit
Still relevant for large apps with complex state logic, time-travel debugging needs, or teams familiar with it.
const counterSlice = createSlice({
name: "counter",
initialState: { value: 0 },
reducers: {
increment: (state) => { state.value += 1; },
decrement: (state) => { state.value -= 1; },
}
});Decision Matrix
| Criteria | Context | Zustand | Redux |
|---|---|---|---|
| Bundle size | 0KB | ~1KB | ~11KB |
| Boilerplate | Low | Very Low | Medium |
| Re-render optimization | Poor | Excellent | Good |
| DevTools | React DevTools | Redux DevTools | Redux DevTools |
| Async support | Manual | Built-in | RTK Query/Thunks |
| Learning curve | Easy | Easy | Moderate |
My Recommendation
- Simple shared state (theme, auth): React Context
- Medium apps: Zustand
- Large apps with complex state: Redux Toolkit or Zustand
- Server state: Always TanStack Query (not in your state manager!)