There has been a lot of talk lately of why Redux is not a good option anymore for state management, and why we should use hooks & the React Context API.
As a Redux user, I want to settle the war between Context API & Redux. So let the battle start! βοΈ
Why Redux
Redux got popular for a few reasons:
- easy to test
- unidirectional data flow makes it deterministic
- state is read-only
- changes are made with pure functions
- huge ecosystem
The problem Redux wanted to solve is predictable state updates. Knowing where and why the state changes and having a "single source of truth" can be an advantage.
I personally think the biggest advantage is testability.
Big apps are constructed on top of lots of tests. π€
When applications grow past a certain size, it is pretty obvious no engineer will know exactly what all modules & tiny pieces do.
That's where tests come into place. Tests are the foundation of good software. And Redux code is very easyΒ to test.Β
Redux proved to be battle-tested in big React apps. Those apps will be around for a long time and continue to use it. Almost half of React apps use Redux (according to polls and dev surveys) - so you can probably figure out why it's so popular & unpopular at the same time.
The Redux ecosystem
Redux has a large ecosystem of tools and nice things that can help developers do other things than state management. This is a shortlist, for a more extensive one look here.
Debugging
Side effects
- redux thunk - for async state handling
- redux saga - awesome for complex async flows, based on ES6 generators
- redux observable -RxJS-based middleware for Redux
- redux persist - pretty much as the name states - persists the stores so you don't need to load everything again next time the user will refresh the app - making it an offline-first app
Integrations
- redux socket.io - for using the popular socket.io realtime communication library
- redux react firebase - firebase integration
And many, many others....
What to consider if using Redux
Beware of anti-patterns:
π making global state out of state that should have been local
For example, making form data global - that's just silly. The form data has no value after it is submitted to the server.
π server state - think if what you are storing is just server state instead of global application state, and in those cases consider solutions as react-query or swr. Those tools have things like Auto Caching + Refetching built-in.
π State duplication - this is a general state management problem. You should avoid duplicating state if possible and instead derive it where needed.
π Doing state updates outside the reducer
Don't do this:
const initialState = {
complexObjectArray: []
}
const badPracticeReducer = (state = initialState, action) => {
switch(action.type) {
case "UPDATE": return {...state, ...action.payload}
<span class="nl">default</span><span class="p">:</span> <span class="k">return</span> <span class="nx">state</span><span class="p">;</span>
}
}
const nextState = badPracticeReducer(initialState, {
type: "UPDATE",
payload: someArray.map(createComplexObject)
})
Learn best practices
An exhaustive list of Redux best practices and things to avoid can be found here - compiled by the Redux maintainers.
Should you learn Redux in 2020?
Yes - if you want a React job it's a 50-50 chance that the company you go to uses Redux for its product.
But not just because of that - the concepts that Redux became popular for - unidirectional data flow, pure functions, immutable state updates are still worth learning and will make you a better software engineer. π
What about Context API?
While I was also advocating for the Context API for new applications, I am not doing it because I don't like Redux or I don't acknowledge the benefits of using Redux.
I am simply advocating for the solution that will have less complexity for new developers. Using Context API is easier than Redux because it will always go together with hooks that you already know like useState
or useReducer
.
Redux adds an extra layer of complexity to our application that we carefully need to weight.
Conclusion
I would say Redux is a good candidate for applications of high complexity. Also when the libraries in the Redux ecosystem make sense (for example - if sagas make it easier to reason about complex async flows).
When working with people newer to the React ecosystem and you don't really need the things from the Redux ecosystem I would go with Context API.
Top comments (57)
Hi :) Since I got quoted here, I'd like to add some additional, er, "context" to the discussion :)
The big thing here is that Context and Redux are very different tools that solve different problems, with some overlap.
Context is not a "state management" tool. Its only purpose is to make a single value accessible to a nested tree of React components. It's up to you to decide what that value is, and how it's created. Typically, that's done using data from React component state, ie, useState and useReducer. So, you're actually doing all the "state management" yourself - Context just gives you a way to pass it down the tree.
Redux is a library and a pattern for separating your state update logic from the rest of your app, and making it easy to trace when/where/why/how your state has changed. It also gives your whole app the ability to access any piece of state in any component.
So, yes, you can use both of them to pass data down, but they're not the same thing.
For more details, see my posts Redux - Not Dead Yet! and React, Redux, and Context Behavior
I'm so happy to have a Redux maintainer comment here! Thanks for the additional references!
I'm glad somebody really stands out and puts such great resources around Redux and how it should be used.
I'm aware of and agree about the Context camparison - that it's not ok. Context is just a dumb provider of storing data in a React Component that is then passing it to anywhere in a React tree. Now to be fair, Redux is also the kind of library that is letting you do most of the work, and it is just imposing some simple rules.
Probably I did not make this article a lot of justice not stating the many anti-patterns or ugly things that can be created using the Context API - as having the tens or hundreds of context providers in your app :).
Wow!!, this is a whole right perspective of why Redux is still important!
Many React devs I've met would choose Context API as the default way to manage global state. Little did they know is that without setting Context API properly, it could affect the entire application's performance.
I came across a problem where Context API would re-render every child components that it wrapped. Even memoizing the child components would still cause them to re-render. This was a big no-no for our application since it is data-heavy and will keep on growing in the future.
With Redux, it allows my team and I to debug the application easily, separate the UI layer away from the data, and be able to understand what is going with the application at all times. It is the tooling and mindset of Redux that many developers do not understand why it is such a great library. They focus too much on the boilerplate code, but in reality, it's that boilerplate code that makes maintaining the application a breeze.
Sure, not everyone needs Redux for a blog page. But when you are dealing with an application that will grow and be used by many users, you need a convention defined for you and your team to follow. When you can manage and understand the state, the actions and the UI separately in your application, only then will you appreciate Redux's beauty.
I think it comes down to size of the application I've mentioned this on another thread/post before. Your post even touches on it to some extent but if you need a highly testable code base using state/Context can make it much harder. This is because you have to essentially test the component and the state at the same time. With redux you can do these two things mostly independently (you could argue that you still need tests on how your component reacts to certain state updates and so forth).
I also feel like redux 'handles' global state in a much more maintable way for larger applications. However this is pretty much entirely a preference I don't think it's impossible to use Context API/state I think you might just have to be a bit more delligent with how you design your application.
Prior to my most recent project I was using a mix of the Context API and normal react state. However I ran into the problems of testing that I mentioned above. However that's just my two cents I'd be curious to see how others feel!
TL;DR: I feel there is a place for both it depends on the size and testing requirements of a project
Nicely said. With Redux we can have independent tests for 3 parts:
Yeah my structure is usually that of:
I haven't actually got around to trying react-saga and am just using react thunk. But I should get around to trying that out too
I did try both and as a beginner I prefer to go with Context API because it is so easy to get started with and there is no external package to install but after reading this post I understand why Redux might be the best choice for bigger project.
I'm now considering diving in Redux deeper to get more job opportunities later!
Please consider using learning materials from the official Redux website and Mark's blog.
A lot of old Redux videos and learning materials might not follow the latest best practices. Good luck!
Will do, thank you!
After 3 years redux coding, I turn to usie only useReducer + props without Context, that is the most simple solution. If I faced with complex problem, then change useReducer with useSagaReducer, without use any global state.
so i think good to know about redux, redux-saga and choose lightest state management for your app - depend complexity.
I had no idea of the
useSagaReducer
hook, pretty cool!As of 2020 I keep reading everywhere that Redux should be used anymore, but I fail to find what to replace it with. The closest I found was someone who reimplemented Redux with useContext and useReducer, but to me it just feels like a doing a new worse Redux? (No proper logging, time travel, observables...)
Even Dan Abramov says he hates Redux but never suggests a proper way to replace it... Maybe it's because the global store is now considered a bad thing?
Give a try to Effector. Its framework agnostic tiny reactive library, wich come with selectors and thunks/sagas out of the box.
After a three year's of redux/mobx and some apollo, effector is just a breath of fresh air for me.ππ
Thanks! I'll check it out when I get some time!
I think it's nice that the core React team is not suggesting something in particular. If they would have done this, it would have hurt the ecosystem for sure - as it would limit innovations and cool ideas. Redux aside, there are a ton of other very cool state management libraries like MobX, Recoil, Zustand, and many more.
GraphQL is an option. Now while GraphQL is not a replacement for Redux it does help to reduce the need for using it.
If the APIs we are using are providing GraphQL then sure! I would not require an API team to build a GraphQL API only for a frontend application. There needs to be multiple consumers or higher business value for that GraphQL API, otherwise, we cannot justify the added complexity server-side.
Great article, some fantastic points.
I've seen (in another article) coding using Redux and code using Context side by side, and I noticed how similar they actually were - the version using Context also used immutability, reducers, actions etcetera ... the amount of boilerplate saved was minor. Coupled with the fact that, as your application gets bigger, you probably want Redux anyway, I wonder why then not choose Redux right away.
On thing that make Redux complex to work with is managing and manipulating state in an immutable way, which gets complex fast. But the funny thing is that you have to do it anyway, also with Context and with useReducer. The code to manage state immutably can get hairy fast but there are tools/libraries to make this easier.
(one complexity that I feel Redux does have is in its numerous "side effect" management libraries such as Thunks and Sagas, this is adding to the learning curve)
But one thing is absolutely true, you're right that you highlighted this: don't push state into Redux which you can just as well make component-local! I think that's where the biggest pitfalls are.
The good news is that our official Redux Toolkit package eliminates all the "boilerplate" around using Redux. It includes utilities to simplify several common Redux use cases, including store setup, defining reducers, immutable update logic, and even creating entire "slices" of state at once It also sets up the thunk middleware by default, catches accidental mutations, and more.
I just published a brand-new "Redux Essentials" core docs tutorial, which beginners "how to use Redux, the right way", using our latest recommended tools and practices like RTK and the React-Redux hooks API. I'd encourage you to check it out:
redux.js.org/tutorials/essentials/...
That's brilliant, just incredible, I wasn't aware of these tools and documentation.
Right, I see that
immer
is included, Redux Thunks is included by default, there are standardized ways of creating the store, actions, reducers ...This makes everything so much simpler, in large part because it's opinionated, which cuts out huge amounts of discussions, confusion, and "choice fatigue". I say it's about time ... discussion, flexibility and "choices" are nice, but productivity and speed are nicer!
Redux has really matured, so I know what I'll choose for my next project.
Yep, that's exactly why we created Redux Toolkit :)
That's a nice move!
I can imagine the difficulty and frustration of understanding redux for beginners, especially if they don't have CS background to back up with many concepts (software architecture, best practice, data flow...). However you're very right on saying that people should consider it, as there is 50% chance that they will meet this at the job. Many apps aren't built today and they have grown big, and it costs the company a lot of money to rewrite or convert it to newer version, not to mention, from a business perspective there is no incentive to do so if the purpose is just to make it easier to developers!
This is the same as Svelte vs. React, no matter how amazing I personally think Svelte is, the job perspective is much lower than React at the moment. So I would learn React first, try to get a job, and have fun with Svelte in my spare time. Until I become a senior who gets to decide what to use, I guess have NO SAY on what to use at all. I just have to follow whatever they prefer, right? :)
Hi Annie, as a Svelte enthusiast I know what you say. I wonder if there are big apps out there build with Svelte. There is also this issue here: github.com/sveltejs/svelte/issues/... .
Yeah within the community we're discussing about showcases. It seems there are some relatively big apps, but they're not widely known. The thing is, only more people are using this, there can be more contribution for bug fix or extra libraries. I see in the report the interest to learn Svelte is quite high, so it's a good sign. :)
Haing some showcases would surely bump those numbers even more over the years, as technical decision makers look for technologies that are proven in the industry most of the time :)
Context API shouldn't be considered as a replacement for Redux. It's an alternative for classic callbacks to parent at most. It's not a state manager. If some dude says that Context will replace Redux, he's living in a fantasy. I can bearly see how to compare those two
Maybe it's dying specifically in React applications
Context (or some small library based on it like Constate), Zustand, or other solutions (or combinations thereof), and now definitely keeping an eye on Recoil.
It's also worth noting that RXDB (albeit with a lot of dependency bloat), can handle not only persistence and sync, but all of your app's state management (even if its creator said it's not a replacement for Redux in an issue comment a long time ago), if you're smart about your use of storage and in-memory together. There same is true of Firebase, AppSync, Apollo, etc.
While I've avoided Redux in my own projects for over a year now, and would personally reach for easy-peasy if I did feel like I needed Redux (I never want to look at Redux boilerplate PLUS Saga boilerplate again, just to do async at that), it's still important to know if you're looking for work (there's a good chance it'll be your employer's state management of choice).
And despite my gripes about it, Redux still does it's job and does it well (except async, that's ridiculous) in an incredibly small amount of code - it may seem like bloat compared to just context or smaller libraries mostly based on it, but it's really very small for what it does and the extensibility it offers (the boilerplate, on the other hand, definitely adds up).
As I just linked above, check out our official Redux Toolkit package if you haven't yet seen it.
Redux Toolkit is good. I should have mentioned that along with easy-peasy.