React State Management: Redux vs Context API
When to reach for the heavy tools and when simpler is better
The question everyone asks
Almost every React project eventually reaches the point where props are being passed three or four levels deep, and someone asks: "Should we use Redux?"
My answer has evolved from "Redux for everything" to something more nuanced.
When Context API is enough
The Context API shines for:
- Theme toggling — user preferences that rarely change
- Authentication state — current user object, login status
- Locale/i18n — language and formatting preferences
- Feature flags — simple boolean switches
const ThemeContext = createContext<Theme>('dark');
export function ThemeProvider({ children }: { children: ReactNode }) {
const [theme, setTheme] = useState<Theme>('dark');
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
);
}
Context re-renders all consumers when the value changes. For infrequent updates, this is fine. For frequent updates, it becomes a performance problem.
When to reach for Redux
Redux (or Zustand, Jotai, etc.) earns its complexity when you have:
- Complex state transitions — state that changes in predictable, documented ways
- Derived state across many components — selectors that compute from raw state
- Server state caching — though React Query handles this better
- DevTools requirements — Redux DevTools are genuinely excellent for debugging
// Redux slice for a shopping cart
const cartSlice = createSlice({
name: 'cart',
initialState: { items: [], total: 0 },
reducers: {
addItem: (state, action) => {
state.items.push(action.payload);
state.total += action.payload.price;
},
removeItem: (state, action) => {
state.items = state.items.filter(i => i.id !== action.payload);
state.total = state.items.reduce((sum, i) => sum + i.price, 0);
},
},
});
My decision framework
Does the state need to be shared across many components?
└─ No → useState / useReducer is fine
└─ Yes → Does it update frequently?
└─ No → Context API works
└─ Yes → Does it have complex transitions?
└─ No → Zustand (lightweight)
└─ Yes → Redux Toolkit
The honest answer
In 2025, for most projects I'd reach for Zustand before Redux. It's 80% of Redux's power with 20% of the boilerplate. Reserve Redux for large team projects where the strict patterns pay off in maintainability.
For server state specifically, TanStack Query (React Query) removes the need for either when the state is remote data.