Redux – Not Dead Yet (2018)
blog.isquaredsoftware.com
blog.isquaredsoftware.com
1. Note that most of the time the stakeholder is yourself and/or another developer. But can also definitely be a non-coder.
https://github.com/zalmoxisus/redux-devtools-extension/blob/...
I work on an app that has a total of about 400 separate Redux actions across half a dozen reducers and a couple of stores. There's a lot of things that cause side effects. Being about to see what actions fired with various props is immensely useful for debugging. redux-devtools and Reactotron are immensely useful. You're right that the majority of React apps don't need to trace actions, but when you do you definitely won't think it's overrated.
I think Redux is overrated because it is used by a lot of applications that don't need it.
I’m genuinely curious because I feel like this kind of inflation of actions/reducers in Redux is what makes it nightmarish.
The standard form is incredibly verbose, I've started to shift away from it.
[0] https://redux-toolkit.js.org/api/createAsyncThunk
[1] https://blog.isquaredsoftware.com/2020/02/blogged-answers-wh...
The company I'm currently working with is the first time I've used sagas / observables / "anything async is through side effects". I've constantly been saying "this is madness, this giant block of code, all these concepts, all this room for things to go wrong, just to do a `fetch`?". It's also the first time in a few years of using redux I've had to deal with race conditions.
Edit: Oh, and you can even `await dispatch`! All the things I've been doing in Redux for years and told I shouldn't, now being officially endorsed.
I'm not going to go in to detail on HN, but the app I work on is used to make diagrams for the legal industry and to define how they change over time. It's sort of like Visio for lawyers, with a basic animation editor that understands the underlying data. There are a lot of actions simply because it does a lot of things that can't be generalised in to higher level actions (well, they could, but it'd be messy.)
That's 76 actions just for the NFS/CIFS-as-a-service UI.
(I'm not saying this is the best way to do it, but that's what's happening right now.)
it's also not clear how this is a replay to the above...
Regardless, yourself or another developer as the “stakeholder” in this scenario is a bit of a cop out. In the real world stakeholders aren’t technically inclined and even if they are they don’t care about this minutiae.
I tried to avoid it but your post just brought out it of me.
I think a lot of developers start off the same way. Idealistic, starry eyed recruits eager to put their knowledge to use and make a product better than they found it.
But then you realize life’s too short to bother with things like Redux. We’re not building software to last thousands of years, there’s no future archaeologists who are going to spelunk through our ancient code and be in awe at the ingenuity of our primitive minds.
We’re lucky if we’re writing software that lasts a couple quarters. Especially when you’re building front end UI, you can expect whatever you do to be completely bulldozed by whatever trend or framework comes along.
So don’t care. It’s not your job, you’ll be paid regardless. If someone wants me to care about a project, they need to pay me extra. Because caring forces that project to take up space in my mind and takes attention and focus from other things I actually want to care about, such as getting my work done and meeting objectives. Early on I used to care so much it would actually interfere with my ability to get things done in a timely manner.
And when co-workers turn around and shit on you for slowing them down, and you see they don’t care either and still get the same pay and recognition, or maybe even more in some cases, you realize there’s no point. That’s not how this business works. Don’t be a hero.
By now I’m so experienced with React I don’t need some time travel debugging tool to tell me shit, even with very complex state. I never have. If I run through an error a few times and throw some console logs I can quickly find and solve the problem 99% of the time. A valuable skill.
I first wrote it back in 2018, and just updated it yesterday with some additional links and comparisons.
(Actually was considering retitling it after getting some feedback last night, but given that the link just got submitted here, I'll leave it as-is for now.)
A few quick notes:
- If you haven't looked at Redux in a while, please try out our official Redux Toolkit package [0], which is now our recommended approach for writing Redux logic, and the React-Redux hooks API [1]. We're going to be teaching both of those as the default approach for using Redux going forward.
- We have a new "Style Guide" docs page that gives our official guidance on suggested usage patterns [2]
- On that note, I'm working on an ongoing major rewrite of the Redux core docs [3]. My current task is creating a new "Quick Start" tutorial, which will be a "top-down" intro to using Redux to stand alongside the existing "bottom-up" tutorial sequence. The goal of the Quick Start section is to quickly introduce Redux concepts, and show RTK and hooks as the "right way to write Redux code", without going into the details of how it works under the hood, so that folks can get started now and learn the underlying aspects later. I've an early partial WIP draft PR up [4], and hope to finish the first draft in the next few days. Once the Quick Start page is done, I'll be turning my attention to rewriting the main tutorial sequence in order to remove outdated terms, clarify explanations, and teach simpler patterns (like using "ducks" files instead of splitting code across multiple files).
If anyone's got questions on anything I wrote in the article or otherwise Redux-related, ask away!
[0] https://redux-toolkit.js.org
[1] https://react-redux.js.org/api/hooks
[2] https://redux.js.org/style-guide/style-guide
What's happened with me (and others I've seen) has been discovering Redux, falling in love, and thinking "I'll use it for everything!" There's something about the simplicity of having a single state tree, that is immutable and debuggable that just blows your mind.
Then you start building, and after writing your Xth action/reducer/selector/dispatch/etc, you tire of the boilerplate and the overhead.
So where I've landed is: 1) we use Apollo/GraphQL for data-fetching and caching. 2) we use hooks in general. 3) for deeply nested component communication, we haven't fully settled on whether to use redux or not and kind of mix it up depending on the circumstance 4) we use redux when we need app-wide state and/or debuggability (so everything that's not 1, 2, or 3).
This has worked pretty well for us, though (3) is still a little fuzzy.
Anyway, I do think Redux is awesome, so thanks for maintaining it. But just wanted to chime in that I think a lot of "Redux is dead" sentiment (besides just being article click-bait and sensationalism by publishers) is actually people realizing that they've done the "everything is a nail" thing and retreating a little bit from that.
For the record, I've never wanted _everyone_ to use Redux, and I agree with criticisms that Redux has been frequently over-used.
All I want is for folks to look at their use cases, take the time to evaluate tools, and make intelligent decisions about what tools best solve their problems.
Unfortunately, the nature of social media and the development community just doesn't seem to work that way. No one seems to write posts saying "here's a new tool, here's how it compares to existing tools, and here are the tradeoffs involved and the use cases where they might each be relevant". It's always "LOL TOOL X IS DEAD NOW!", even if Tool Y is brand new and has 10 downloads and 2 GH stars while Tool X's daily downloads continue to increase.
We were actually thinking of migrating to something similar in terms of data fetching to Apollo/graphql and leaving redux for more app wide state problems.
Could you share any further insights on how you started organising this project? I.e. some pieces in Apollo/graphQL while maintaining a redux core, (presumably that's the core you started with?). Would be really interested.
Also I share your sentiment exactly, redux isn't dead. It's still a really solid approach to state management, and in complex applications I still think it's one of the best options. Thanks and kudos to the maintainers!
I encourage everyone to try out redux toolkit if you feel like redux is too much boilerplate. It also comes with immer out of the box, so no more crazy spread operators.
Also the 'reducks' pattern of splitting the Redux state into separate files, each containing a reducer and the related actions and selectors helps keep things simple to understand (although I guess it is a bit more overhead, actually).
- Immer makes writing immutable updates easy, because you can write "mutating" logic like `state.todos[5].completed = true`
- `configureStore` sets up a Redux store with good defaults (DevTools extension, thunks, mutation checking) in a single line of code and has easier-to-read options if you do need to tweak the config
- `createSlice` eliminates the need to write any action creators or action types by hand
- Our new `createAsyncThunk` and `createEntityAdapter` APIs (new in v1.3.0 [1]) simplify the common use cases of dispatching actions as part of data fetching and managing normalized data in your state
Also, RTK is written in TypeScript, and designed to infer as much as possible. For example, if you declare the type of the action payload in a `createSlice` reducer, the generated action creator has its payload argument typed automatically to match.
Meanwhile, the React-Redux hooks API generally requires less code than `connect` does, and is easier to use with TypeScript as well.
Finally, we're now encouraging folks to use the "ducks" pattern for single-file Redux logic [2], which cuts down the number of files you might have to work on for a given feature, and using `createSlice` basically gives you ducks files for free [3].
[0] https://blog.isquaredsoftware.com/2019/10/redux-starter-kit-...
[1] https://github.com/reduxjs/redux-toolkit/releases/tag/v1.3.0
[2] https://redux.js.org/style-guide/style-guide#structure-files...
[3] https://redux-toolkit.js.org/usage/usage-guide#exporting-and...
How do you handle testing of connected components? There’s tons of pain points. I’m on a pretty large Redux project too, and every day I wish I could just simplify the whole app (as we scale) by removing Redux.
I think it speaks volumes when the Redux maintainers are going into a direction that uses less boilerplate, like Redux Toolkit.
Honestly, there's nothing wrong with boilerplate, but I guess it's time to admit that some people love it and others hate it.
Dispatching actions and writing reducers is _inherent_ complexity. It's part of Redux's design, and is a deliberate level of indirection.
Having to write nested spread operators to perform immutable updates, switch statements in reducers, and `const ADD_TODO = "ADD_TODO"` is _incidental_ complexity. Nothing about Redux's core design _requires_ you to write the code that way. There's valid reasons why those patterns exist [1], but writing a reducer with a switch statement vs a lookup table doesn't change how the Redux data flow behaves.
My goal is to eliminate the incidental complexity, because it's not necessary and does present a barrier to people learning and using Redux.
[0] https://blog.isquaredsoftware.com/2019/10/redux-starter-kit-...
[1] https://blog.isquaredsoftware.com/2017/05/idiomatic-redux-ta...
IMO the biggest and best draw of Redux is how it allows you to completely separate your business logic from your UI layers. Your components only know about props and state and are rather trivial to test. Hooks are great for re-usable logic as well but my team made the choice to have hooks deal only with localized state concerns and have a robust Actions => Services => Reducer layer for everything that speaks to things outside that constraint. Its worked out wonderfully so far. Tests are a breeze and logic is highly portable. Our UI layer is thin and easy to change.
Its not all roses of course. The Redux store can turn into a rats nest of keys and values with no obvious structure (or worse, duplicated structures). It's something that requires actually sitting down and modelling out your data structures. Sadly that's something I don't see very often (and I am just as guilty as anyone else). The Redux team came up with some good guidelines on this point (too lazy to track the link down but its on the main site) and I think they have some really good ideas. I think more than anything its important to consider your store in the same manner you would a database and approach it with that kind of mindset. As with all things JS, its easy to dive in, hard to untangle yourself! :)
I use createActionsHook below in every actions.js file... combined with thunks, it's awesome imho.
IMO the only downside to your approach is that it couples your action creators to the calling component. That isn't necessarily a bad thing but it all depends on what your particular goals are. If you intend to have your action creators as a kind of "super prop" that is specific to your caller and disposable and single purpose in nature, I think that works. To be successful (again IMHO) you'd want to segregate your business logic outside of that layer into either the reducer (as the redux team recommends) or in a service layer that the actions can talk to (my preferred approach). As always YMMV.
Yes and to keep it normalized. IMO, Redux is incomplete without some sort of selector layer, which acts as the metaphorical database views.
[0] https://redux.js.org/recipes/structuring-reducers/normalizin...
- the ability to create a middleware that is your analytics listeners. Analytics will listen to actions and spit out analytic info when those actions trigger. Because of this there is literally no analytics code anywhere in your codebase, except encapsulated in that one analytics middleware and sub-tree.
- Ability to just see every state update in dev tools which is AMAZING for tracking down what caused a non-obvious problem. For example: Was it a bad api request? Was it a bug in the reducer? etc. Hard problems suddenly become easier with good debugging tools.
- Ability to persist a part of the store to local storage. This is actually quite nice.
However, I definitely fall into the cluster of people that were "just told to use Redux". For my next React project I will certainly evaluate other approaches.
I think it's even more important for people self-learning react to be exposed to redux in some way; yeah, there's boilerplate, but it's just beautiful when all put together and isn't a Blackbox (I love dan's tutorial on egghead explaining redux from the ground up precisely because it breaks down exactly what's working and why it is).
This blog post does an excellent job of convincing newcomers in the JS world to consider learning redux. I'm definitely forwarding this to the current instructor of the course!
Are there any popular alternatives which don't use reducers?
EDIT: thanks for all the responses, I'll check them out :)
You may be happy with just using hooks, though.
(Yes, thank you, edited.)
I can implement this thing in vanilla JS, and it would not take more than a few milliseconds. React is cool, but so damn hard to optimize.
React's default behavior is that when a component renders, React will recursively re-render _all_ of its descendants. it then diffs the VDOM render output to see if you've asked for any changes to the UI since the last time it updated. If the two VDOM trees are the same, React says "nope, nothing to do here!", and ends the render pass. _If_ you requested changes, it then gathers them up and applies them all to the DOM in one step.
You can optimize the rendering behavior in some ways if needed. The `React.memo()`, `PureComponent`, and `shouldComponentUpdate` APIs [0] allow you to tell React to skip re-rendering if you know that a component's props haven't meaningfully changed, and thus would result in the same UI output as the last time. This does require that the child components be separate component types (ie, `<MyComponent />`), not just the parent rendering a bunch of plain elements (like `<div>`).
For lists in particular, React needs to know how to identify which items are which. React doesn't care about object references, but you can pass a special prop called a `key` when rendering items in a list. That way, if you move a list item up, swap a couple others, delete one, and add a couple more, React knows what existing list items ended up where, and can update the DOM efficiently in response. Otherwise, changes to lists without good use of keys can result in more DOM work being done than actually necessary.
https://github.com/jamiebuilds/unstated https://github.com/dai-shi/react-tracked https://github.com/react-spring/zustand https://github.com/diegohaz/constate
(there are more, but these may be among the most popular)
You can find a comparison (and more) here: https://github.com/dai-shi/lets-compare-global-state-with-re...
[No affiliation with the project]
I personally love mobx-state-tree (and mobx!). I really wish more would not jump straight for redux/etc without giving the powerful abstraction of observables via mobx a shot.
Super simple, 100% test coverage, 100% typesafe if using typescript, absolutely no boilerplate.
I think the addition of React's hooks and context api actually make Redux easier to use, and I like the purity of its role as a state manager. I personally find that its cleaner to keep the overall application state in redux than to hold onto it inside of React, and leave react to manage its own component's state regarding ui level interactions.
Much better to break your app state into various custom hooks that leverage Context API and the `useReducer` hook.
I'm trying to make a few specific points:
- Redux is not "dead" in the sense that it is still widely used and is continuing to be adopted
- There are definitely many other tools in the React ecosystem that overlap with how you'd use Redux, but the Venn diagrams for the use cases don't entirely match up, and the other solutions don't necessarily have all the capabilities of Redux
- Redux _has_ been over-used and put in apps where it didn't fit well, and I want people to only use it when it makes sense to do so
- Our Redux Toolkit library and React-Redux hooks API make it a lot easier to use Redux
‘ - Redux _has_ been over-used and put in apps where it didn't fit well, and I want people to only use it when it makes sense to do so’. ‘
There are developers working day in and day out in these Redux codebases so our feedback is coming from a real place. There’s a million articles that pushed Redux to the top and got it used in just about everything. Articles just like this one.
This article is literally pushing back against all the reasons why Redux might not be a good fit. There’s very little in it that goes ‘yeah you know what, for this scenario, don’t use Redux’.
- I have no control over the millions of other tutorials that have been written. I can only control my own blog, and the actual Redux docs.
- The question of "When does it make sense to use Redux?" has been answered numerous times already [0] [1] [2]
- I wasn't trying to address the "when?" question in this article. I was trying to answer "is Redux still a viable choice, and how does it compare to other alternatives?"
I've written plenty of 6-10K word blog posts about Redux before that delve into how and when to use it. That wasn't my goal for this post.
[0] https://medium.com/@dan_abramov/you-might-not-need-redux-be4...
[1] https://redux.js.org/faq/general#when-should-i-use-redux
[2] https://blog.isquaredsoftware.com/2017/05/idiomatic-redux-ta...
CSS, SASS, redux, array.reduce, webpack are examples that come immediately to mind from the javascript world. There have been so many throughout the years
So let’s see how this blame game works, because I have a hunch you want to aim it at people that think Redux is a bad choice.
You are suggesting that people that really don’t like Redux actually don’t know how to use it properly, misuse it, go down that rabbit hole and come out completely jaded by it. They then go on to provide their feedback, to which the obvious dismissive response is ‘well maybe you don’t know what your’re doing’. So the bad mouthing is actually occurring from the other side, no?
For the last few years, any job post you saw related to React, Redux was a prerequisite for probably over 90% of those posts. In other words, Redux was gospel, not the the feedback of naysayers. The mass broadcasting was happening by the framework adopters to the point said framework became ubiquitous.
Lastly, there’s very little feedback about Redux that has to do with people’s understanding of it. Almost the entirety of feedback is coming from usage of Redux and noticing by-products of using it (bloated code base, needless complexity - and this needless complexity criticism is ripe for being sniped by the framework advocates as a symptom of essentially incompetent developers who can’t see the elegance of Redux. The feedback is that it’s not elegant ).
The thought leaders are not the people providing negative feedback in this thread and elsewhere. The thought leaders, the gospel creators in this case are these Redux based articles/advocates that prolifically spread Redux throughout the React ecosystem to the point it became a standard dependency for every app.
In this case, this is a very real situation where it needs serious push back because it spread untethered and unexamined.
One thing I also want to point out, the same way the developer community has a responsibility to evaluate the proper usage of a technology, those who partake in pushing certain technology also have a responsibility of analyzing the impact of what they are evangelizing. One could argue it is irresponsible for influential subsets of the Javascript ecosystem to push a layer of complexity for apps that do not need to make the trade offs for a few features.
But, as I noted just above this comment: we don't control the rest of the developer ecosystem. All we control is the official docs, and our own blogs and social media comments.
I also want to emphasize that we _haven't_ dismissed people's feedback as "you don't know what you're doing", and in fact have tried to take that feedback into account with our docs and the creation of Redux Toolkit, to guide people in the right direction as they use Redux.
Nope. Neither implied nor intended.
The article is a reasonable reaction by a redux maintainer to the dynamic I describe. "I don't like using Redux" is a totally valid opinion. "Redux is terrible" is, frankly, not a valid opinion. Neither is it valid for CSS, javascript, React, Vue, Pascal, COBOL nor what-have-you, and yet here we are yet again, letting fickle winds of fashion and facile opinion dictate what should be engineering decisions.
Use redux if your use case applies. Don't use redux if it doesn't. If you find it unwieldy, dont use it. I wish the tech community could leave it there, but they don't.
The last couple years I have been using the new Context API and spliting my app state out by creating a global context, and many domain specific contexts where the context contains both the data and functions used to work with that data. Typescript + state with data and functions created a great api per domain. I found this approach just as clean but with less boilerplate.
Though redux does have some performance and tooling benefits.
Yeah, the boilerplate setting up the middleware and initial reducer isn't fun... but it's been really rewarding and the react-redux hook has been a godsend.
const store = configureStore({reducer: rootReducer})
https://redux-toolkit.js.org/usage/usage-guide#simplifying-s...You'd still have to pass in options for whatever persistence addon you want to use, but that would be something like:
const store = configureStore({
reducer: rootReducer,
middleware: [...getDefaultMiddleware(), myPersistenceMiddleware]
})
Which is still shorter and easier to read than having to mess with `applyMiddleware` and `compose` yourself.[0] https://redux-toolkit.js.org/api/getDefaultMiddleware#includ...
I've used mobx and it's better. Now I use apollo, and it's even better.
Just thinking about having to use redux and sagas and all that bloat makes my stress levels rise. I can't believe it became as big as it did.
"muh time travel" is a meme of epic proportions.
- redux pollution (not cleaning up state and things leaking)
- because you can't access redux state directly, components have to copy redux state and store them as props (which makes 0 sense, its state not props). But now you run into the issue where the local prop is not in sync with redux since redux updates are correctly done in chunks.
Components have always been able to extract whatever data they want from the store using the `connect` API, and now our new `useSelector` hook. Those APIs return whatever values _you_ want for use in the component, and that generally is the actual object references to the real data that's in the store.
Both `connect` and `useSelector` subscribe to the store and re-run the logic you've provided whenever the store is updated, and force a re-render of your component with that fresh data. If I have:
const user = useSelector( state => state.users.entities[props.userId])
Any update to that specific `user` object in the store will cause this component to re-render. Same goes for `connect` and `mapState`.So yeah, your statement confuses me, because it doesn't seem to describe how React-Redux actually works.
So, I don't understand what points your parent comment is trying to make, because the whole point of React-Redux _is_ to keep your components in sync with the data in the Redux store state.
Switched to using a shared model class instance - the value is changed immediately and anyone who needs to know the latest version can do it easily. Much simpler, faster and easier to debug since there is truly only one source of truth, not copies everywhere.
I'm also not sure why you keep using the phrase "copies". The Redux store has the only actual copy of that data, and your `mapState/useSelector` functions typically return the actual references to that same data. The only copies made are if you make them yourself. Also, the value in the store _is_ already updated before any of the UI subscribers are notified.
Can you put together a sandbox that reproduces this problem and file an issue? I'm very curious what you're actually seeing.
Most people have simple applications so redux works fine, but once you get complicated async work things just break down.
https://redux.js.org/faq/organizing-state#should-i-put-form-...
Reading through the comments it sounds like it's struggling, even positing the question sews doubt. I thought redux was still one of the 'must have' tools for building react apps now.
What has everyone been migrating to? Is there a consensus successor to Redux?
1) React's Context API
It's straightforward to use, and it solves the issue of passing data to deeply nested components, but that's all it does.
2) GraphQL Apollo Client
I used this on a recent project for managing client-side state, and to me, it felt like I had to do a lot of work to achieve what should be basic functionality. It was my first foray with Apollo Client, so take my opinion with a grain of salt, but I found myself wishing I was using Redux instead for the duration of the project. Also, Apollo Client has some bugs related to cache invalidation (look on Github). These may be solved now, but they bit me pretty hard.
3) The new React "Hooks" API
Looks nice. Have not used it.
There's a huge difference between all the chatter on social media, and the actual stats reflecting Redux's usage.
Two charts to illustrate this:
First, overall downloads for React, Redux, React-Redux, MobX, and Apollo Client over the last two years:
https://npm-stat.com/charts.html?package=react&package=redux...
You can see that net Redux usage overall has continued to increase, and is holding fairly steady at about 50% of React downloads.
Second, for Redux Toolkit specifically, the growth rate from just before we released `redux-starter-kit@1.0`, then renamed it to `@reduxjs/toolkit@1.0.4`, through today:
https://npm-stat.com/charts.html?package=%40reduxjs%2Ftoolki...
Obviously way fewer total downloads, but that's a steadily increasing growth rate for RTK.
This is not something that's "struggling". There's just a lot of FUD thrown around on social media that makes it sound that way.
why post it again?
(tbh I'd forgotten it actually hit the front of HN when I wrote it the first time!)
i’ve been wondering the state of things as im jumping back into react projects after a couple years off.