I know that popular opinion in the Twitterverse is that "Redux is dead", but I note that both Twitter and Slack just released major rewrites that use Redux heavily.
I talked about Redux usage stats and comparison with other alternatives in my "State of Redux" talk at Reactathon earlier this year [0], and my post "Redux - Not Dead Yet!" also addresses some of these aspects [1].
Also, quick plug for our current focus. I'm working on some tutorials for our new Redux Starter Kit package [2], and then will be working on tackling additional functionality to push it towards a 1.0 release [3].
After that, we'll get started on a major revamp of the Redux docs [4] to improve the learning flow, better organize the content, cover more real-world usage topics, and teach using Redux Starter Kit as the "default way to write Redux".
Thanks for the articles! We've been using Redux since August of 2016 at Groove. For us, we've found that Redux makes sense when you have state that needs to be shared. If you are dealing with some specific, tightly coupled component state, it sometimes makes sense to keep that particular piece of state local to the component (at least for our use-case). The biggest issues we've run into during our time with Redux have been 1. not being atomic enough with our connected components (sometimes passing massive objects down the component tree instead of selecting what we need at each point), 2. running into leakiness in react-redux (such as function arity changing short-circuit caching behavior in the mapping functions, forgetting to invalidate components when using select factories, etc), and 3. not normalizing our store enough (which contributes to #1). As we continue to mature in Redux, we are slowly fixing #1 and #3 in our codebase. We are still sometimes getting bitten by weirdness in react-redux though. I'm not sure I have a solution, but I think there is still a lot of opportunity for improvement there. And not just in react-redux, in helping developers understand how to properly build performant redux-driven apps in general.
Yep. The Redux "Three Principles" docs page [0] emphasizes the "single source of truth" aspect. It's a good selling point, but has unfortunately led to a lot of folks interpreting that as "you _must_ keep _everything_ in Redux". (Doing so is a valid design decision, and I've certainly talked to folks who deliberately did that to make everything trackable and time-travel-able. But, most UI state probably doesn't need to go in Redux, particularly form state [1].)
In reality, there should be a good balance between global and local state. I wrote a Redux FAQ entry that tries to give some rules of thumb for determining what state goes where [2].
When we do the docs revamp, hopefully we can make that kind of thinking more explicit.
I'd be very interested in hearing more details on any issues you may be having with React-Redux, and I'm happy to offer advice for you or anyone else on using it better. HN comments aren't a great place for that, but please file an issue for discussion or contact me in the Reactiflux chat channels on Discord in the #redux channel.
I'd also greatly appreciate any feedback folks would have on weaknesses with the current docs, so we can improve those issues with the docs revamp.
We've had open issues to cover writing a "Performance" docs page for a long time, but no one got around to contributing that, and there's been too many other higher priorities for us to write it. My React/Redux links list does have a section of articles on improving Redux perf [3], if that helps, and there's an FAQ section on that topic [4]. In general, connect more components [5], and use memoized selectors [6] to read data and do transforms.
> The Redux "Three Principles" docs page [0] emphasizes the "single source of truth" aspect. It's a good selling point, but has unfortunately led to a lot of folks interpreting that as "you _must_ keep _everything_ in Redux".
After a couple of years working with Redux, I think my interpretation has settled down to:
Redux should be the single source of truth for the pieces of information you decide to put in there.
I recently came to the conclusion that I’ve been going a bit overboard with this in ClojureScript's (let’s call it equivalent) version of Redux, re-frame.
Rather than putting absolutely everything in the global DB, I now try to restrict that to things that are actually global, such as the user profile data and such.
Isn't the common sentiment now that Redux is no longer considered a must-have for all greenfield projects?
Also aren't communication apps a perfect use case for Redux due to the need to have events from multiple sources happen in a single store in a linear order?
That's part of what I was getting at, and what I talk about in the first couple links.
Lots of folks have used Redux because they were _told_ they "need" to use it. That's always been overkill. And, yes, there are plenty of other viable alternatives that overlap Redux's capabilities in various ways (Apollo, MobX, React context, etc).
So sure, it's not a "must-have", because you should _always_ evaluate tools and determine what's really appropriate for your use case rather than just blindly using something.
But, at the same time, Redux is still very widely used (~50% of React apps), and not going away. So, there's a big difference between "not an automatic must-have" (which is true) and "dead/dying" (which is not).
I am not super knowledgeable about all the exact architectures, but I thought mobile was just starting to adopt the redux architecture vs MVP, MVVM, etc
A lot of people are saying that the new-but-not-really-new React Context API and useReducer hooks are sufficient to cover redux. My team isn't convinced, we see immense value because we're big fans of using Redux Saga-- a model that isn't well covered using Context or hooks, although we do use those APIs as well when needed.
Suspense for data loading seems to cover that side of things quite well in the experiments I've tried with the current API.
I use Sagas as well though, and Ive found them ok...really easy to test but feel very heavyweight and clunky; personally, I don't _really_ like the loading/error state to be handled by Redux: the more years I work on React/Redux app the more I prefer for a section of an app to be mounted -> triggering a fetch -> loading, show local loading UI -> {fails, show local UI|succeeds, dispatch success}. So Redux becomes a serializable normalized data cache that acts to store the results of disparate API calls and doesn't care at all much about the UI.
There's a tremendous amount of work out there for how to get redux to completely handle async and branching methods, and I think the best solution for most cases is to not have it handle any of that.
Keep your data fetching in normal everyday functions, have react components call those and funnel the data you need in the global store back to redux, and then have the components that need that data read it from the global store.
The results are in the Redux store. I'm not sure I understand the question, why and how would multiple components be making the same fetch request at the same time? With what I'm describing, there is already a common state, if they just need access to that state they have access to it.
Edit: If you do need to synchronise multiple async updates to that state that happen in a very short space of time & in an unknown order in a controlled way, then yeah something like sagas is a solid choice to exert control over that. But very often the user of the UI is only going to make one request [or one batched set of requests] -- eg I am working on an RN app at the minute, and each screen does need to fetch data. So I fetch in the component, it shows loading etc, then populates the store. If the user cancels what they're doing (navigate away for example), the component used to fetch unloads and no dispatch is made.
That was me! Component level fetch !== no Redux, that's not what I described; using Redux does not _mean_ you have to use one of the many libraries built to wrestle asynchronous fetching into Redux.
I've got nothing against any of them, I've used almost every major one in my jobs over the last few years. But I (and the person who replied to me) both seem to feel the same way, that in many cases just fetching in React, in the component, is all that is needed, let the Redux application deal with marshalling the resultant state (which it is very good at)
I have preferred this method myself when dealing with simple calls (calls that need no further external information). jumping through 7 files just to find the API request that gets shipped is slightly insane.
but how do you put the result back in the store? how about displaying a default failure screen?
> jumping through 7 files just to find the API request that gets shipped is slightly insane.
The API request is in the file that represents the point at which the API request is made by the user (previously in a loader component or, now, using a hook, in future using suspense), so I would say it involves jumping through 0 files, as opposed to several if I move it to redux (the dispatch occurs at the UI trigger point, then I have to drill through several other layers of abstraction). In practice there's normally some facade in front of the API to prefill values and also to make it easier to mock for testing, but if anything that just makes it simpler as the facade acts as a reference.
This is I guess down to a preferred philosophical approach but from my pov React is a UI library and it's _really_ good at showing conditional UI. Redux is a state container and is not great for this. I don't feel I want that in Redux, I want Redux purely to be a reference the state of the data in the app; loading/req/etc states are not that. Whenever I've moved error/request/loading/failure state to Redux (ie almost every app I've made over the past four years before this year) it involves a series of abstractions to track the current request. Whereas React can do this out of the box at the point the action is taken: make the request, show some state, if the request succeeds, dispatch the data to the store and [re]render the component that displays the data based on the state of the store.
> but how do you put the result back in the store?
dispatch({ type: "foo", data: "bar"})
And have a component that renders based on props in the store, same as normal.
We started a greenfield project a few months ago and decided not use Redux and try the context API instead. In retrospect, that was a bad idea. Context is fine for a small app, but small apps tend not to stay small... and then you're stuck with the Yugo when you what you really need is a truck.
In our main app we also use advanced features like what Slack is describing in their post, like having multiple Redux stores. We also combine stores from multiple sources (e.g. appStore = [...store1, ...store2, ...storeFromALibrary]. It's incredibly flexible.
Hooks are definitely going to reduce a lot of greenfield project needs for a state library, which should be great for React ease of starting new projects.
Something like Redux Saga, Redux Thunks, Redux Observable (my personal preference here), or what have you, are the higher order "toolsets" that Hooks alone aren't likely to replace yet. It may be the case that some of them are going to start targeting Hooks/Context more directly without "needing" an intermediary state engine like Redux, but it's also entirely possible that it will still remain a good reason to make a step change to a state engine like Redux when you find yourself needing higher-order coordination between components that libraries like Sagas, Thunks, or Observables can provide.
I think once you grok sagas, they're very difficult to replace. I think it's such a neat mental model to be able to dispatch global actions and having async tasks able to respond. I think it leads to nicer decoupling in components between UI & data.
Under the hood it uses [cofx](https://github.com/neurosnap/cofx) which is a library I wrote to solve the need to write declarative side-effects without redux.
I wouldn't say Redux is dead, but there are a number of alternatives. My team has switched from Redux to MobX for all new development, as the two libraries solve the same problems, and we find MobX a bit easier to work with for our specific use cases.
There's nothing wrong with Redux; we just found that Redux based code tended to have a fair bit of boilerplate, and it wasn't as easy to maintain code using Redux as we would have liked. Every dev team has to find the right place to draw the line on implicit versus explicit, magic versus verbose, convention versus configuration. No real right or wrong answers.
> I thought mobile was just starting to adopt the redux architecture
I don't think so, no. The Redux architecture (ie, reducers, actions, etc.) is fairly specific and not universally loved. I would say that people are starting to really grasp the importance of solving the problems that Redux solves, however.
I encourage you (and everyone facing the same problems) to take a look at Rematch (https://github.com/rematch/rematch). It's Redux (the real Redux, you can even use it with the Redux-DevTools) with a MobX-like syntax. And already comes with async support.
My only request for redux-starter-kit is more documentation on usage with TypeScript (and perhaps deeper integration with ts-not sure how well the current package integrates with a ts codebase).
RSK should be fairly usable with TS. As I understand it, it can't be as magically strict as `typesafe-actions` is or infer quite as much automatically, because of how we're generating the action types from the reducer names as strings. But, it should definitely generate correctly typed action creator functions for you.
I talked about Redux usage stats and comparison with other alternatives in my "State of Redux" talk at Reactathon earlier this year [0], and my post "Redux - Not Dead Yet!" also addresses some of these aspects [1].
Also, quick plug for our current focus. I'm working on some tutorials for our new Redux Starter Kit package [2], and then will be working on tackling additional functionality to push it towards a 1.0 release [3].
After that, we'll get started on a major revamp of the Redux docs [4] to improve the learning flow, better organize the content, cover more real-world usage topics, and teach using Redux Starter Kit as the "default way to write Redux".
[0] https://blog.isquaredsoftware.com/2019/03/presentation-state...
[1] https://blog.isquaredsoftware.com/2018/03/redux-not-dead-yet...
[2] https://redux-starter-kit.js.org/
[3] https://github.com/reduxjs/redux-starter-kit/issues/82
[4] https://github.com/reduxjs/redux/issues/3313#issuecomment-45...