All posts

React State Management: Redux vs Context API

When to reach for the heavy tools and when simpler is better

React State Management: Redux vs Context API article cover

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:

  1. Complex state transitions — state that changes in predictable, documented ways
  2. Derived state across many components — selectors that compute from raw state
  3. Server state caching — though React Query handles this better
  4. 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.