State Management: Redux vs. Context vs. Chaos

Do you really need that massive Redux boilerplate? A guide to making your life easier (or harder, if you're into that).

ReactReduxContext APIZustand

State management in React is like choosing a restaurant for a group dinner. Everyone has a strong opinion, nobody is happy with the final choice, and you end up paying too much for something you didn’t really want.

In the beginning, there was setState. And it was good… until it wasn’t.

The Redux Era (also known as “The Boilerplate Age”)

Then came Redux. It promised a “single source of truth.” It also promised that you would need to write 47 files just to toggle a button.

  • Action Types: TOGGLE_BUTTON
  • Action Creators: export const toggleButton = () => ({ type: TOGGLE_BUTTON })
  • Reducers: A switch statement that looks like it’s from 1995.
  • Store: Keep your provider close, and your middleware closer.

Don’t get me wrong, Redux is amazing for complex apps. But using Redux for a todo list is like buying a semi-truck to carry your groceries. It works, but everyone is staring at you.

Context API: The “Built-in” Solution

Then React gave us Context. “Look!” they said. “No more prop drilling!”

And we rejoiced. We wrapped everything in Providers.

<AuthProvider>
  <ThemeProvider>
    <UserProvider>
      <SettingsProvider>
        <NotificationProvider>
          <TheActualApp />
        </NotificationProvider>
      </SettingsProvider>
    </UserProvider>
  </ThemeProvider>
</AuthProvider>

Welcome to Provider Hell. It’s warmer than callback hell, but just as cozy.

Enter the New Contenders: Zustand, Jotai, Recoil

Then came the new wave. minimalist, hook-based stores.

Zustand

Zustand is German for “state” (I think, I don’t speak German, I just write code). It’s tiny, fast, and doesn’t require a Provider wrapper.

const useStore = create(set => ({
  bears: 0,
  increasePopulation: () => set(state => ({ bears: state.bears + 1 })),
}))

Look at that! No reducers, no providers, just bear population management. Simple.

So, what should you use?

Here is my highly scientific decision matrix:

  1. Is it a hackathon project? Use useState and prop drill until your fingers bleed.
  2. Is it a medium-sized app? Use Context or Zustand. Please, for the love of clean code, try Zustand.
  3. Is it Facebook? Use generic Flux architecture or Relay or whatever they use now.
  4. Do you enjoy pain? Use Redux with raw plain JS (no toolkit).

At the end of the day, the user doesn’t care if you used a globally distributed atomic state machine or a global variable attached to window. They just want the button to click.

But you have to maintain it. Choose wisely.