The React ecosystem has spent the last few years trying a model where the application layer separated from the view layer with a pure functional state management solution called Redux. The overwhelming response? People didn't like it.
Decoupling systems is a trade-off. Pull your network requests out of your components and you have two bits of code that are easier to test. Indirectly, the component is still going to call that code, and it's up to you to manage the complexity of that indirection.
Not every application needs separation of concerns, and in many, colocation of concerns reduces the cognitive burden, because you can reason about components in isolation. To me, that's a more powerful guarantee than a function being strictly pure.
Hi, I'm a Redux maintainer. I've written extensively about the fact that A) Redux _has_ been overused, B) that many of the complaints were really more about the standard code patterns needed and the "boilerplate" involved, and that C) "modern Redux" with our official Redux Toolkit package and the React-Redux hooks API has solved those "boilerplate" concerns.
Redux is still by far the most widely used state management tool with React apps (my estimates are around 45-50% of React apps use Redux), and we try to give clear guidance in our docs on when it does and doesn't make sense to use Redux.
FWIW, we get highly positive feedback on a daily basis from users who tell us how much they love using Redux Toolkit.
Acemarke isn't just "a Redux maintainer", he's incredibly active on Reddit, HN, and Discord, helping people understand Redux better, and also, when it doesn't make sense to use it.
I can't speak to his code contributions, but in terms of documentation, tutorials, and community engagement, most open source projects would be lucky to have similarly prolific contributors.
FWIW I _have_ written actual code in the libraries too :) I wrote React-Redux v7 by myself, shepherded the design of our hooks API in 7.1, and did all the coding work for v8. Also created Redux Toolkit, added a couple additional APIs, and a bunch of other stuff :)
Yeah, concerns about Immer have come up a number of times. The usual concerns people have are:
- Too much "magic" as you said
- Proxy-wrapped data values can be harder to inspect in the browser's debugger
- Seeing "mutating" code may be confusing
I understand those, but from my perspective the benefits of Immer far outweigh any potential negatives.
Ultimately all Immer does is track attempted mutations to nested data, and replay them to create the immutable updates as if you'd done all the nested spread operators yourself. There were dozens of immutable update libs in the ecosystem already (I had listed most of them in my Redux addons catalog), and accidental mutations have always been the number 1 cause of bugs in Redux apps. So, a better way to write immutable updates was clearly valuable.
Immer drastically simplifies all that update logic:
- Removes all the extra object spreads and slices and concats you would have had to write previously, so the code is much shorter and easier to read. It's also more clear what the actual intent of the state update is.
- It also completely eliminates accidental mutations _in_ reducers, and also _out_ of reducers by freezing the state.
So, shorter code, easier to read, and eliminates the #1 cause of Redux bugs.
The tradeoffs are a couple KB of bundle size (which is quickly paid for by having shorter reducers), and needing to understand that Immer is there and doing this "magic" for you.
The one still slightly nagging annoyance is that inspecting Proxy-wrapped data in a debugger is painful, but Immer does supply a `current()` util to extract the plain JS data if you need to, and we document doing that:
Thank you for the detailed response! My experience seems to be different, as in my opinion immer solves a problem that should not arise in nice code (in most cases) - state should not be that deep anyway. It also takes away a bit of the simplicity of Redux which is its greatest strength, imho.
But as I said, I still highly recommend Redux Toolkit. After dealing with the code using MobX and the complexities brought by its reactions, I would take Redux anytime. Immer is just a small unfortunate detail, but I can live with it.
> Kudos on Redux Toolkit! Anyone who complains about boilerplate with Redux has obviously not tried the Toolkit version.
You still have to understand Redux's weird boiler plate concepts - actions, action creator functions, reducers, thunks, ... - to understand and use Redux toolkit. Redux is broken from the bottom up.
This was exactly my reticence... back when I was learning various approaches and trying to come up with a first-principles derivation of which way to go, I came to the conclusion that I wanted to avoid immer like the plague. So discovering that RTK requires it has made it difficult to consider embracing.
I'm very curious, what concerns do you have about Immer? fwiw I just wrote a sibling comment that goes into some detail on what problems Immer solves and why we included it in RTK:
Still worth it though, imho - if you have a chance do give it a try. It makes Redux much less verbose and is an ideal abstraction for state management. It never bothered me that much, but forking Redux Toolkit and removing Immer is still an option if you feel strongly about it (should probably be easy).
That wasn't supposed to read as a criticism of Redux. Redux was just popular enough to be the medium where people discovered that you pay a price for the indirection you need to keep view and state separate.
It won't ever be a one-size-fits-all solution and unfortunately, Redux will have to live with the legacy of plenty of users finding that out the hard way.
That being said, I think Redux Toolkit is a great improvement to the vanilla experience and I'm always impressed by how much I see you out and about on the internet weighing in on these kinds of threads. Inspiring stuff!
I'll add to that: I love redux and most of the complaints or concerns that I've heard about using redux (from a few teams) have been misunderstandings of how to integrate redux into an existing application or an application design. I think this has mostly come from junior-level folks (independent of title, there are a lot of non-junior devs who can't integrate new patterns into their "senior" level understanding of code, but I digress) and folks who don't work on the front end much (or ever). I was one of those folks until I started a side-project that used redux and I had to implement it in a greenfield project and had the liberty to refactor as I progressed and my mental-model "updated" to integrate the new framework.
My complaints with redux were that people couldn't leave it alone. At least in my experience, there was a lot of middleware or libraries built on top of what was a conceptually very simple library.
Using the redux-toolkit and the hooks, with none of the additional junk is a great experience.
The biggest thing I miss in react ecosystem is decent redux ORM. https://vuex-orm.org is just so great for so many use cases (agree that it might an antipattern in many situations). Is there any chance that https://github.com/redux-orm/redux-orm, which was actually what inspired vuex-orm, would get more love from anyone to become an actively maintained library?
Great question. I actually was one of the earliest users of Redux-ORM, back when I myself was first learning Redux in 2015-16, and I wrote a blog tutorial series in 2017 that showed how to use it.
At the time, the main benefits to using Redux-ORM were easier immutable updates for items in the store, keeping items in a normalized state structure, and managing relationships between items for both lookups and updates.
Since then, Redux-ORM has changed maintainers and had its API tweaked. Meanwhile, we added a `createEntityAdapter` API [0] to RTK, which handles normalization and some CRUD-style updates to the data. Even without those CRUD helpers, you can still do `state.entities[itemId].someValue = 123` thanks to Immer, so immutable updates are taken care of.
At this point, the one remaining thing that Redux-ORM really handles that RTK doesn't is that specifically relational behavior - ie, given a `Post`, look up all its `Comment`s by an array of IDs or something. You can do a decent amount of that with selectors, but yeah, Redux-ORM's API here is nicer.
We haven't tried to provide any of that ourselves because this becomes a much more complicated and app-specific topic. But, I'm always open to suggestions for APIs and use cases. If you have ideas for things that we should consider adding to RTK, please do file an issue so we can discuss details!
That figure is "Weekly Downloads", not in total. None of them had updates in less than two months. Also, React has published 10x more versions than Redux. So if anything, Redux might be more popular than GP assumed.
My estimates are primarily based on NPM download stats for React, Redux, and React-Redux, as well as more anecdotal evidence like "what libs are you using?" polls that I see on Twitter and such.
These are all obviously _very_ imperfect proxies for actual usage stats, but they're all that I see available to work with.
FYI my last attempt to estimate "React state management market share" was in a Reddit thread earlier this year, with download numbers and caveats included:
A big challenge with the React ecosystem is that it's the first technology many new developers work with. They don't have a frame of reference for what alternative approaches exist, and therefore 'best practices' are taken on faith and followed blindly until their nuances can be learned through experience.
That's not a bad thing (and it's better than the alternative of not caring for design patterns whatsoever). It's part of the learning process, and since there are so many beginner developers who are using React, their perspective is much 'louder' than in other dev ecosystems.
You can see this in the absurd amount of introductory-level React content posted to Medium, DevTo, Twitter, etc. This has bred a very strong 'follow-the-leader' culture where, when the one person is the room who _does_ know what they're talking about makes a statement, others will repeat it verbatim without understanding its nuances due to a lack of experience/context.
Redux suffered heavily from this. New React devs in 2017 were faced with mountains of tutorials which all used Redux. Many of these tutorials were written by other newbies. Your mental model of React dev was then shaped around Redux. Therefore you would put everything you could into the Redux store, which is a bad idea -- you usually don't need form state in there, for example.
Then some React thought-leaders saw this problem and inadvertently created a counter-movement by raising how Redux was overkill for some use cases, which was misconstrued as 'you shouldn't use redux _at all_'. The pendulum has been swinging back and forth ever since.
Yes, not every application needs separation of concerns. But some definitely do. It's not black and white, and that unfortunately means there's no definable 'best practice' that can be tweeted or blogged about and followed blindly -- it just has to be learned from experience.
I would go one step further and say that the counter-movement is the visible effect of newcomers discovering that separation of concerns was a bad decision for the simple apps they were building.
Or maybe more accurately, discovering that it's often simpler to separate by concern at the component level, than at the app level.
We all ride the pendulum until we find the shade of grey which works best for us.
Like, I don't want _everyone_ to use Redux. I just want people to understand "here are the strengths, weaknesses, and use cases of tools X, Y, and Z, and when it may make sense to use them".
Honestly, we Redux maintainers (Dan, myself, Lenz Weber) have had to spend far more time telling people when _not_ to use Redux than we have trying to advertise the library :)
When I rewrote the Redux docs tutorials last year, I made it a point to put "When should I use Redux?" right up front on the first page:
> Therefore you would put everything you could into the Redux store, which is a bad idea -- you usually don't need form state in there, for example.
Why's that? IME it is usually simplest to just put everything in redux. For example, if you have a form under some kind of tab navigation thing, you'd ideally want the form state to be preserved even when they tab out and then back in. Putting it in redux means you don't really have to think about it
But this could also just as easily be solved by moving the form state up, or at least the preservation of each tabs state one level up, without using redux at all.
You'd still preserve on tab change just as easily, while using just reacts mental model.
I agree with your point that not every application needs this degree of separation of concerns. But the problem, in my experience, is that individual developers are not very good at knowing where that line is. And the line can move over time as the application grows.
For any project that I'm responsible for, I don't feel comfortable designing around a paradigm unless there are some guard rails to prevent developers on my team from accidentally tying the code in knots. How enjoyable is this for the developers? Are they sprouting angel wings and playing the lyre as they write code in iambic pentameter? Probably not, no. They have less freedom of motion than if they were left to their own devices.
This is a larger debate: where to fall on the spectrum between unadulterated developer bliss and having an application that is still maintainable in 5 years. I don't put much stock in developer bliss, but I do appreciate that the sword cuts both ways.
Sorry, but I have stopped using "developers don't like this" as a measure of the technical quality of anything. A lot of developers like things that are pleasurable to them in the small, but harmful to the codebase in the aggregate, especially over years of maintenance cycles.
I'm not sure I agree with this. One of the elements of a well-designed system (whether we're talking about software libraries or anything else) is that the designer should reward people for doing what they like. If you design something where the correct approach cuts against people's natural inclinations, they'll just use something else. The correct answer is to design paradigms that make the right thing pleasurable.
I agree that systems should be rewarding to the user. But there are rewards and there are rewards. There are short-term dopamine fix rewards, and then there are the rewards that you can only really appreciate after having invested some time and energy first. It's like fast food vs a lifetime of diet and exercise.
The churn in the frontend ecosystem reminds me a lot of fad dieting: people have never really experienced working in a paradigm that enables them to stay healthy through regular diet and exercise over the long term, so they turn to the latest shiny gizmo hoping that this time it will be different.
I agree with you that there's a balance to be had here (although I will note that there's a pretty big difference in physiological effect between tens of thousands of years of evolutionary history and a few years of writing code). That being said, I don't think we should make "rewarding to the user" a second-class citizen to "technical quality" - I think it's an important component of good technical quality that something is pleasurable to use. My impression is that a lot of self-serious systems designers don't embrace this view because it's easier to blame the technical incompetence of their users.
I'm writing this stuff to try and push back against the whims of that majority, because I think they're ill-founded. Just because a majority of people believe something to be good and true, doesn't automatically make it so. It still has to stand up to empirical evaluation on its own merits.
This is true, and especially true for tutorial and course authors. There are a lot of low quality tutorials that are essentially a dev talking about how they prefer to wrute code rather than teaching any useful, generic material that applies universally. Often what works in their courses for a lone junior dev would not scale to a small team, and following their ideas would produce a pretty terrible app.
I've been reading "blue" DDD book (by Eric Evans) and "red" book (by Vaugh Vernon) and that was a completely "my whole life was a lie" type of experience and relief at the same time. It's just so great to have the principles of who to structure the code. It, by definition makes, your codebase structure meaningful. Because it's structured according to some common knowledge, not your random thoughts at the time you were writing code.
I was surprised to find so little DDD react sample codebases. Let's say for backend there is huge amount of samples, i.e. https://github.com/kgrzybek/modular-monolith-with-ddd . For react/frontend I have bookmarked only https://github.com/talyssonoc/react-redux-ddd/tree/master/sr... and few more, but those others does not meet the optional criteria i like really much - at the highest (or at app) level all codebase need to have folders app, domain, infra and ui. Simple rule, but simplifies life a lot.
So my question is - is DDD for some reasons not very applicable for app frontend development. Or it just never became popular. Or maybe DDD is popular amongst react developers, just I am not aware of this.
idk if “the overwhelming response” is people dont like Redux. some people are very vocal about their dislike, yes. But 1/3 of survey respondents use Redux despite other choices existing. theres a reason it won the Flux wars.
It won the Flux wars, but there are state management approaches based on paradigms other than flux. There's at least the model that Recoil/Jotai uses (atoms?), the model that MobX/Valtio uses (mutable observable state), the model based on state machines (XState), the model heavily using React context (Constate), etc.
Maybe overwhelming was too strong, but I don't see many people getting excited about building new projects with Redux any more. Presumably some proportion of that 1/3 are stuck on Redux, unwillingly?
I like (and use) Redux on a daily basis, and I don't think it's a sensible choice for lots of React apps. Maybe the overwhelming rejection that I've witnessed is people discovering that they used it for stuff they shouldn't have.
The React ecosystem has spent the last few years trying a model where the application layer separated from the view layer with a pure functional state management solution called Redux. The overwhelming response? People didn't like it.
Decoupling systems is a trade-off. Pull your network requests out of your components and you have two bits of code that are easier to test. Indirectly, the component is still going to call that code, and it's up to you to manage the complexity of that indirection.
Not every application needs separation of concerns, and in many, colocation of concerns reduces the cognitive burden, because you can reason about components in isolation. To me, that's a more powerful guarantee than a function being strictly pure.