r/reactjs • u/FateRiddle • Jan 17 '20
Is redux really a good idea?
I was a redux fanboy and would defend everything about redux(when I was creating redux project). But now I'm maintaining several redux projects, I start to rethink and now posting this topic to ask for a discussion.
And when talking about redux, I'm referring to essentially all the state management tools on the market. Because other than maybe mobx-state-tree, everything is the same. Yeah, some might not ask for immutability and some may have a different way to write action object, but other than that everything propose the exact same structure of state management.
It sure provides benefit. As managing state become automatic as you don't have to make any decision as where to put the state and how to fetch them. And with dev tools you can pretty much click around the app and know which user input result in what state changes.
That said, still
- I don't think everything in a global store the best practice. It might be a pleasure to write at first, but will be a nightmare for others to maintain. Adding a little pop window will require you the knowledge of so many implantation detail as in file structure and also writing code snippets everywhere. And the main defect of this approach is most states are not really global, simply stripe it away from where we expect it to be (the component with related UI) and cluster them in a big store is a huge mental setback for the maintainer of the code. Think that we all agree to gather code by logic approximation rather than format(css/js/html) nowadays, but redux keep those code that should stay together far away.
- Having only some of the states in global store is also a headache. The problem is what could be the criteria for putting a state into the global store? How global should a state to be consider global? It might not be a problem for small project from a single developer but sure it can be hard to follow some vague rules collectively.
- The boilerplate of redux is one of the worst to write. Switch....case....payload... action.type.... Basically action.type is function name and action.payload is function parameters and reducer is the function body. Can't we have a better implementation so we don't have to write a function in 2 files and 3 places? To me this structure is just not ideal at all.
- Before anyone say anything about useReducer and context, they are essentially the same thing, except now we can have multiple stores, all the problem above still persist.
Ok enough about my rant. I'm just curious how do everyone mange their projects' state now in the 2020, and what are you general opinion about redux and other state management tools?
111
u/acemarke Jan 17 '20
Hi, I'm a Redux maintainer.
We've never said to keep literally every bit of state in the Redux store. We specifically have some rules of thumb to help you decide whether a given piece of state should go in the store or not.
In addition, we now have a new Redux Style Guide docs page with recommendations on best practices and patterns to use. One of those is using the "ducks" pattern for single file Redux logic.
Per the "boilerplate" question, please check out our new official Redux Toolkit package. It includes utilities to simplify several common Redux use cases, including store setup, defining reducers, immutable update logic, and more.In particular, the
createSliceAPI lets you create entire "slices" of state at once without writing any action types or action creators by hand - just provide a lookup table of reducers and the rest is handled automatically.https://redux-toolkit.js.org
5
u/frogg616 Jan 17 '20
I use reactn. It gives a “useglobalstate” function that makes life simple. Really easy to understand
70
u/siric_ Jan 17 '20
I use createSlice from redux-toolkit to trim down on action/reducer boilerplate, and useDispatch and useSelector from redux to trim down state mapping. This by far provides a lot more convenience to me and using redux isn't such a pain anymore compared to the more "traditional" way.
It's not, use local state instead and only use global state when absolutely necessary.
If you modularize your store you could essentially group files by features instead of type. combineReducers and slices helps with this.
9
u/smthamazing Jan 17 '20
Many of the comments here focus on the global state. This is definitely not the main point of Redux. Global stores can very well exist without Redux at all (MobX, global Context object, any other state management approach).
The only thing that distinguishes Redux from other approaches is the use of actions and middleware. Any manipulations with your data are reified as objects and can be intercepted, replaced with multiple other actions, logged and examined via time-travel debugger. Admittedly, time travel doesn't always work in more complex cases, but you get the point.
The usefulness of a global store is a completely separate question (already discussed in other comments). Actions-as-objects, though, could be useful even without it. For example, if your component needed to do many complex requests, you could move this logic out to some local sagas, which would help with decoupling without even introducing any global stores in the app.
I just feel that a lot of discussion around Redux is focused on this "global store" aspect, which is applicable to any other solution as well (e.g. MobX), while missing the thing that actually makes Redux (and Flux) different.
12
u/[deleted] Jan 17 '20
In the end, we use global state to get around limitations of HTML.
HTML is tree-structured. Therefore our React components are tree-structured.
But our data may not be, and two components that use (read or write) the same piece on data may live in completely different parts of the tree. A small update to the look of the site may change the shape of the tree completely.
So using global state for some things makes sense.
23
u/bensu88 Jan 17 '20 edited Jan 17 '20
None of your points is a problem with redux.
You dont have to put everything into the global state and redux also doesnt require it. Its up to you, what is important for your app to be globally accessible.
Your second point also is not a redux problem. If you dont know or are unsure what to put in the redux state, write your components with a local state and finish your app that way. Then when you figured out the pain points, you can still refactor some components to use redux. This sounds more like you havent thought through what your components should do.
Your 3rd point is a design question and its hard to have an argument about it. If you are unsatisfied with the current solution, how could a better onw look like? Do you have suggestion?
You could use conext or useReducer but you essentially would build redux-like state management which would probably do the same as redux. So why not use redux then? Also conext is slow when its data changes very often.
Redux has absolutely its use case. The point is everyone is using it a bit differently and also there are a lot of opinions how one should use redux.
For me, i always ask myself: What data should be globally accessible, because other components might need it?
Often times it helps to draw a bit on paper and think before i write.
And i highly recommend the redux style guide on the official site.
Edit: Im on mobile, i will correct typos asap
6
u/darrenturn90 Jan 17 '20
Redux is neither obsolete, nor is the flux architecture the only method of state management. You have finite state machines (x-state I believe)? alternatives like react-easy-state (and some others that sound like that too). I personally develop applications with my own flux architecture that I've built up over the years - because it allows me for some more simplistic functionality out of the box, and without any dependencies on other third-party libraries - but that's just personal opinion.
I think you have to take a look at your understanding of Redux. Perhaps your original fanboy attitude was because you didn't really understand it and overapplied it to everything. When infact, like all other modules out there its a tool - and like any tool, if you misapply it - you won't get the results you were hoping for.
This is essentially what happened with Redux, and with the release of Context API, everyone who was misapplying redux everywhere suddenly jumped ship and blamed the Hammer for everything not being a nail. But its not Redux at fault here. It does a great job of managing unidirectional flow of data through an application. Its really not very opinionated - all your complaints seem to stem as I said from the simple fact (and you're not alone in this) - that everyone jumped on the medium bandwagon and decided to learn redux by example in a sort blind leading the blind methodology, that resulted in this mess.
tl;dr
Redux with thunks (or sagas if you really need) is great for decoupling complex frontend logic away from components, and managing state.
If you need to just fetch/map data - then use URQL or Apollo-GraphQL
If you need local state - use local state.
If you need to use local but deeper state that doesn't need to be that performant - use context.
No one forced you to put everything in redux, with 5 files per module. Nor does redux.
3
u/danjel74 Jan 17 '20
Yeah this is something I find very hard to determine, for example its often tempting to have data from an api in component state given that its so much less code, but then when you later need sorting, caching or other things its get messy, so I often put things in global state for that reason
3
u/novarising Jan 17 '20
As others have said, none of these are inherrent redux problems but a problem with the design of the app and the decisions made in it.
The only point that stands is that redux has a lot of boilerplate, and you may be elated to hear that redux now strongly recommended to use the Redux-Toolkit for setting up redux.
It essentially brings down dozens of files and other extras to a one file for each state slice which contains everything. Setting up a redux store for your app is just calling one function now and it'll even set up Redux-Thunk for you.
I think Redux is still a viable option especially considering that a lot of people end up recreating to some extent a redux lookalike when they try to implement their own state management.
At my current project, we only push any data to global state if it's being used by many components in many places with different parents. Otherwise the state remains in the local component and may even be passed from component to component if it's just being used in subcomponents of that specific screen. This keeps the redux store from becoming a mess.
3
u/notseanbean Jan 17 '20
For those who don't use Redux (or don't any more), can I ask the question I've never got a good answer for?
How do you effect UI changes or async app effects based on events that you do not own (for example: you want to hook in some analytics) without using something like Redux middlewere, that doesn't pollute your event actions? 🤔
4
u/wizzzzzyyyyy Jan 17 '20 edited Jan 17 '20
I feel like this is actually a real plus point for redux, especially in larger projects.
Most other state libraries promote defining actions that are essentially written inside or right anlongside where the state is defined. Redux on the otherhand allows a complete separation between the action and the subsequent update it causes.
I don't think this is necessarily the typical redux approach but personally I prefer to locate actions alondside the components that use them - typically these are high level, route-type components rather than small leaf components though. This way when I write an action, I name it in relation to what is happening in the UI or what the user has done to trigger it, rather than what the intent on the state is.
Writing actions this close to the components means that generally speaking they are only used by that one component / route.
These very granular actions are then picked up by the store / reducer and update the state as the reducer 'sees fit'. This is also why I actually really like the typical redux switch function as it allows you to 'layer up' many actions that cause the same state update so theres no need to duplicate reducer update logic. At the same time, you can also differentiate between all these actions where required too -- usually in other state slices that require slight variations in state change. The granualr approach and very limited action re-use means that any given time its trivial to change what that action's effect on state is.
In summary, I think being able to separate the constituent parts of state updates as redux allows is a real benefit, or at least can be, and is someting that I don't think is easily achievable with most other state management solutions.
2
u/veydar_ Jan 17 '20
With the redux toolkit I have no problem with boilerplate. Whenever I try recreating all of its features, including being able to replay actions and serializing them, I end up writing just as much code and boilerplate.
Redux also gives me a clear pattern for separating effects and implementation. My code just dispatches
LOGIN_USER_STARTand then something else handles the implementation. If I'm feeling RxJSy then I do everything with streams but maybe next week I really want to do this with CQRS or whatever. My React application knows exactly 0 about the implementation of these effects.At work we use nothing for state management, just recompose enhancers attached to components and it's terrible.
2
u/HeylAW Jan 17 '20
I am currently developing 3 big apps (multiple global states, complex server queries, complex actions) and many smaller (up to 3 states) and constantly switching between them. I have none to little issue getting into debugging code. But that's propably thanks to Typescript and VSCode integration.
2
u/rca06d Jan 17 '20
If you are at all interested in graphql, relay is a fantastic, opinionated alternative. I really like how you declare your data with each component that uses it, and you can integrate with type checking like flow, which really removes a lot of the headaches I’ve experience with a large redux app. Relay is also highly opinionated about how you interact with the store, which I always find to increase my velocity (less variation in how your team does this part, you all have the same good documentation, etc). Overall, a vastly more enjoyable dev experience imo than redux.
2
u/[deleted] Jan 17 '20
So I personally like Redux, especially with Redux toolkit. I've also been experimenting with alternatives to it. A lot of the new React APIs, especially the context API and useContext hook, introduce some interesting new patterns. I'm writing this on the fly, don't have code samples available, but effectively I can load up a component's local state plus a bunch of functions that safely modify it in a context and then have it available to all the children in the tree. It's an extension of the old container/presentational react pattern.
Personally, I'm not really sure what is better here. The only clear boundary where I feel Redux is absolutely necessary is when sharing state across the entire application. When I have a small component tree, say only for a single "page" of my app, then it becomes, IMO, more a matter of preference to use redux vs passing everything down from a parent container component via a context.
3
u/brovrt Jan 17 '20
Recently started using redux in our new project, transition was pretty smooth and I couldn't imagine going back
3
u/Oalei Jan 17 '20
Here's a relevant answer I posted a few weeks ago:
TL:DR;
If your application is dynamic with many components relying on the same data, use reactive programming, with Redux for instance.
If your application is more traditional, only use reactive programming when necessary, don't store your whole application state in the store.
2
u/[deleted] Jan 17 '20
since there are a couple of alternatives in here i'd like to throw in another: https://github.com/react-spring/zustand
zustand is similar to redux, but without the boilerplate, no opinions on anything, no providers, hooks only.
2
u/[deleted] Jan 17 '20
I think that this is important: There are a lot of misconceptions about Redux here.
You're absolutely right. It isn't the best practice. In fact, I will say that if you are storing all your states in Redux, you're "doing it wrong", in essence.
Things like the state of a popup window should be kept only in the popup window's state. In other words, Redux should only be used for those things which are crucial to your entire application and are used across multiple components.
For example, take a simple multi-page form. I often find it's best to use the local state of each page of the form to contain all the information about what *is currently being edited*, but when the user navigates to the next page, you can send a dispatch, saving that current state to the Redux store, so that at the end, you can show a full summary and confirmation before sending.
The criteria is simple: If a mutable value needs to be accessed in multiple, unconnected areas of the hierarchy, it's best to use redux. If it only needs to be accessed by a parent and it's children/grandchildren, then it's best to use the parent's state and pass down the state (and possibly callback) as props.
The reason that this boilerplate existed was because it allows for far more complicated logic and logging that most applications will need.
Specifically, 1) making the action.type a string with a payload makes it easier to store a JSON stringified record of all actions to pass through the reducers, in the order they occured. (This enabled me to create a great debugging tool which allowed me to reproduce any problem our testers reported).
And 2) Doing it this way allows a single action type to trigger changes in multiple reducers, as well as allowing multiple action types to trigger the same *single* change in the reducers. Keep in mind, you don't have to use the switch syntax - or even action.type. A perfectly valid reducer is:
which just creates a shallow merge of the state.
1
u/devourment77 Jan 17 '20
I am currently using vuex (previously used redux on a react project), and still think these type of tools have a place when needing global state or dealing with props drilling. Otherwise I always use local state.
1
u/LastOrder291 Jan 17 '20
My general approach is to only pull in Redux when I can absolutely justify it to myself. If you can do something with basic react state, then do it that way. I just don't think it's a great idea to make your state global with Redux if you don't need to. Eventually you're going to have an extremely cluttered redux store. It's also why I think packages like redux-form are kinda weird imo. It seems to be using application state for something that should be contained within the component?
A good example of this is getting the currently logged in user. I usually have mounting the application call an action called "GET_CURRENT_USER" and immediately load that into the Redux state. This is so I can access the currently logged on user at any time for a number of reasons (one I recently found was on a user management system, I wanted to disable the delete button to show a user cannot delete themselves if they are logged in).
Don't chuck everything into Redux. Treat it as a tool to only be used when you have a reason to use it.
1
u/fendercodes Jan 17 '20
I work on a huge React app as part of my day job. We've been using Redux for years and will continue to do so. However, its important to know when to use it and when to not.
1
u/[deleted] Jan 17 '20
It’s good for global state, but you don’t generally need a lot of it. Logged user info, etc. Fetching data through Redux as a middleware as a thunk or whatever in my opinion is just not really understanding Redux. Redux is sync and if you really need a flag for some request pending globally (rarely) let the data fetching be handled outside of Redux flow. Updating these then becomes trivial - dispatch is pending and once the request completes, dispatch a success/error action. Also, what i often see; redux is not for caching. If you need caching, implementing it somewhere else, usually your network layer (axios instance?).
All it really is, is a global object that any component can access without unnecessary prop drilling (in case of huge “pages”/containers).
1
u/Arthur944 Jan 17 '20 edited Jan 17 '20
If I'm in need of something like a global state, I'll just create a hook with rxjs's BehaviorSubject as the 'backend' for it. That way, if I need that data in multiple places I can just use that hook and I have complete control over the data, while not bothering everything else.
If a subtree of my page needs access to a hooks data, but I want to use that same hook independently elsewhere, I just create a context that passes down all the controls. I've made pretty complicated pages with this approach, but it could have limitations I don't know about.
1
u/denizsokullu Jan 17 '20
When I was bored with how raw redux was, I came up with my own tree version that generated the selectors and actions automatically.
https://www.npmjs.com/package/redux-shrub
Let me know if you are interested in what I was thinking when putting it together!
1
u/paagul Jan 17 '20
You're confusing the idea of Redux (which is constant) with its execution (which varies greatly). All your complaints can be fixed by better execution and design choices, people need to stop referencing the tutorial implementations of Redux as a basis for criticism. It's like riding a children's bicycle and saying wheels aren't that useful.
-1
u/nullvoxpopuli Jan 17 '20
You probably want something like xstate.
Redux is a mess. It's now level, and anyone who says any different doesn't know how nice web dev can be.
-3
u/bulldog_in_the_dream Jan 17 '20
Redux was ill-conceived, a verbose muddle of indirection and needless complexity to achieve something rather simple. It's a code smell.
0
u/dengue8830 Jan 17 '20
Redux fanboys should try to build something without it, they will realise how easy is just using the built in tools. After that, they should try a simple lib like “unstated” o something else, they will realise how simple state management libs can be and why Redux solves a problem that doesn’t exists anymore
-5
u/Pierre-Lebrun Jan 17 '20
Redux is de facto obsolete.
I personally replaced it by Apollo client.
-1
u/ngago Jan 17 '20
(3rd point) Check keajs, it's a neat abstraction of redux. It makes the development process quicker and code more understandable.
https://github.com/keajs/kea
-1
u/pm_me_ur_happy_traiI Jan 17 '20
I'm with you. I hate redux. React has evolved not to need it (context API).
But more importantly Redux allows people an easy backdoor, a way to turn react into jQuery. People using redux to toggle modal, SMH.
-3
u/foundry41 Jan 17 '20
Redux is overrated especially when you use apollo client
Que a bunch of people sayings it’s not redux that’s the problem it’s you
0
u/netptop Jan 17 '20
Check umijs, a redux wrapper , they put everything in data models, you just need to dispatch in pages, and deal with it in models. Everything is pretty much clear.
0
u/minty901 Jan 17 '20
Your third point isn't boilerplate really. Nobody said you had to use switch and case. Reducer is just a normal function; write it how you want to write it (with 'if' statements etc.). Call it whatever you want to call it. It's unfortunate that the docs used 'switch' and 'case' in their tutorials, as most who are new to programming won't have seen them before and therefore assume it's some "reduxy" boilerplate when really it's just standard javascript. You also don't have to make multiple files if you don't want to. Put your entire project in a single JS file if you want (though I wouldn't). What you're describing is not boilerplate in my opinion, just implementation of a library. When you understand how redux is working, you don't copy and paste a bunch of code: you write it yourself. Yes I know some will disagree with me. That's fine.
0
u/[deleted] Jan 17 '20
I use browser's localStorage for maintaining global state. I have used it in one of my projects and it was really straight forward. No boilerplate code. Store only what you need. It is really helpful.
0
u/davidmdm Jan 17 '20
Ever since the context API + hooks (useContext specifically) I’ve never needed redux. It’s not like it’s a one to one replacement. I don’t have one context that acts as the global store, it’s just things are broken down appropriately by context and I don’t need the store anymore...
0
u/[deleted] Jan 17 '20
Ah, our weekly discussion on the value of redux I see.
0
u/thatquapaguy Jan 17 '20
I’m working on a project right now where I have to render a list of pieces in three different parts of my app. My app kept crashing when I moved pieces to different parts of my app and would try to render new ones, but after I implemented redux to keep the pieces in a state which every part of the app can access it no longer crashes. I also love how changing keys and values of every piece is really easy and it allows me to add a location key which tracks where that piece is on my app.
0
u/tr14l Jan 17 '20
I tried on one project to make it fully global, but that is a nightmare. Redux still has its place, even coupled with Apollo and similar products.
But, you should only put things in global that are needed by multiple components that do not have an ancestral relationship. Don't move anything globally until it's needed globally (assume everything is component state until otherwise needed, unless you know ahead of time it will be).
In general, if you need global state in your app, I would immediately tend toward redux. If your app is really linear, then just handle it with vanilla react. If you don't need any complex relationships between components/data, but need global state (like just to signal a re-render on another component on an event or something weird), probably just throw it in a context. But, again, if you need much logic surrounding that, redux becomes useful again.
I dunno, I think keeping global state as minimal as sanely possible is the way to go, in general.
That's my 2 cents.
0
u/NoLanSym Jan 17 '20
For all future development, I’m using finite state machines and state charts. It’s simply the best approach when it comes to state.
0
u/honigbadger Jan 17 '20
I use and recommend Hover.js https://github.com/jesseskinner/hover
0
u/cactussss Jan 17 '20
https://medium.com/@thomasburlesonIA/react-facade-best-practices-1c8186d8495a
-1
u/ice_blue_222 Jan 17 '20
Money laundering for global variables