February 19, 2025

It’s probably time to stop recommending Redux

State management considered harmful

One of the most exciting things about working in the React ecosystem is you can observe, almost in real time, how our perspective on the problem domain of UI development evolves.

When I first got into React, state management was a very important architectural concept. This was I think, because of the struggle involved with sharing state and making things reactive. We’ve learned a lot since then.

Redux was, for all intents and purposes, used on every major project. I suspect its ubiquity today has to do with that. At the time it was a major tool in React: the idea of a global state, something you can access from anywhere without worrying about scope, prop drilling, and unnecessary rerenders.

Redux’s place in the React ecosystem was questioned at the advent of hooks. A lot of different state management libraries came around with seeming great APIs. Zustand had a simpler approach without the requirement of reducers, which made it more intuitive for a lot of apps. Recoil, similarly, went with an atomized approach to state which seemed more modular and sensible. Yet Redux stuck around, reborn as RTK.

A year or two later, React (now Tanstack) Query became popularized. It provided a declarative approach to interfacing with APIs, which felt greatly improved over what was (for the most part) calling services via a run-on-init useEffect. Perhaps more importantly, Tanstack Query included an API cache. Developers began to realize that most of their state’ wasn’t state at all, but rather immutable API data. Yet still, Redux stuck around: now via RTK Query, a Reduxed” API library approximating React Query.

I think Redux, and most other state managers need to go the way of the dinosaur. Especially for normal” enterprise-CRUD applications. It’s not just that they’re not needed, it’s that describing your application in terms of global state’ is often a harmful mental model, bad for modularization and encapsulation. And I’m not necessarily recommending React Context as a replacement! Just… don’t have global state, use an API cache, and use props.

I have written some fairly complex React code. I’ve used React to manage the overworld UI/inventory of a multiplayer HTML5 game. I’ve written financial and healthcare products that required massive redundancies. I’ve written a CRM system that allowed you to design your own UI objects/widgets. And the number of times I’ve actually reaped the benefits of a complex, CQRS style React state pattern is exactly zero. Proper component modularization already provides you the encapsulation you need to separate commands from queries. You know, the way React was meant to be used. In our aversion to prop drilling we forgot what props provide us: a natural interface to separate concerns, instead of adding another dimension of coupling via a global state manager.

User settings?

Derive it from API cache and/or browser cache.

Blog posts?

API cache, URL state, etc.

Client theme preferences e.g. dark/light mode?

Maybe Context! Probably API/browser cache.

A client-specific checkout cart with N-dimensional nesting / subcategories like DoorDash?

useState. Seriously, see how far you can go. I think the complexity of these problem domains are grossly overestimated. I would structure this as a useState wrapped in a custom hook useCheckoutCart which exposes an API to perform various actions like updating items, adding new items, removing items, etc. The mutations on the CheckoutCart’ state are just pure functions.

Literally Figma?

Maybe Redux. Probably not though. Most likely your state will need to be held outside of something in the React DOM altogether and syncronized with peers/remote via sockets/WebRTC. Most of your site is probably on an <canvas>, and the parts that are React (UI widgets, menus, etc) are trivially implementable via something like useSyncExternalStore. For something as performance intensive and bespoke as Figma it’s probably worth building your own state abstraction to handle your specific needs.

But I don’t want to cause rerenders. My app needs to be performant.

I doubt it. React developers talk about reducing rerenders” very flippantly. I think we see rerenders as an arbitrary standard of performance optimization we can naturally strive towards, and it gets in the way of solving real problems. Certainly, you don’t want needless rerenders. But in my experience, performance is something hyper contextual to which there is no silver bullet. It is trivial to memo and use other optimizations to avoid rerender chains in high level parent components, which I find far more valuable for performance than anything a global state manager pretends to afford. Most performance issues” have to do either with lists or complex UI DOMs, neither of which Redux necessarily solves”.

And I don’t just mean to pick on Redux. The same applies to Zustand, Flux, Recoil, Jotai, MobX, etc. State management is a solved” problem domain to which you rarely, if ever, need an external library to handle. What state manager should I use?” if you’re asking the question in the first place the answer is almost always none.

If you’re a strong believer in Redux, or any other state manager for that matter, I urge you to try to manage client state without a library and just use an API cache. I think you’ll find that Redux won’t be missed.



Copyright Nathanael Bennett 2025 - All rights reserved