4 ms·
Redux has several components - actions, reducer(s) and the store. Why actions? Actions give you an explicit API between the global variable manager(the store)
by Sacho 10y ago
Redux has several components - actions, reducer(s) and the store.
Why actions? Actions give you an explicit API between the global variable manager(the store) and your components. For one-off components that are cognizant of the fact they're part of an "App", this isn't very useful - e.g. if you want the component to insert "foo" instead of "bar" into your global state, you just go and modify it. For reusable components, however, their interface may be locked(used by other parts of your app or even different apps!). Then you need some kind of adapter to turn the "foo" they give you into a "bar" - actions are one such adapter.
Besides that, actions are one part of the "state machine" design that redux implements. Actions enumerate the possible ways your state can change. Is your state meaningful if you change global.foo = "bar"? It might be, or it might not. Actions are a contract between those modifying the state and those consuming the state, that all changes to the state will leave it in a coherent...state! Even MobX, which essentially takes your "global variable" idea and runs with it, advocates for actions.
Having this guarantee is great for debugging. Is the global state mangled? The global state manager code must be broken, since everyone sends actions, and the only one consuming the actions is the manager. You don't have to hunt for a rogue component that's setting global.foo = "bar" instead of global.foo = "baz". Once your global state manager is ironed out, your problems are less "why is my state mangled" and more "why isn't the component sending the expected action".
In theory, this should simplify your debugging a lot - you are not trying to disentangle a complex set of interactions that led to your state being mangled and a component failing from that, but rather you're just looking for the one component that isn't sending its actions properly. Redux's debugging tools try to highlight this, with the action logger and so on.
In practice, how useful this is depends on how you've designed your actions and global state manager. It is entirely possible to write a trivial global state manager and essentially place all your logic in the actions(for an extreme example, imagine a state manager that accepts an action "set" with a "key" and a "value" - you haven't actually gained anything then!).
Why reducers? If you're convinced that a global state manager and actions are a good idea, you are now stuck deciding how exactly to implement this manager. Let's say you have a yet-unwritten global state manager. You know the current global state, and you've just received an action. A reducer is function with the signature (state, action) => newState, essentially implementing a global state manager! Redux goes a step further and asks that reducers are "pure functions" and that the state is immutable and replaced instead of modified. The reasoning here isn't specific to Redux and it's once again related to consistency and debugging.
Do you really need all of this? That's a good question, and I think it really depends on the project. You may have heard people advocating that you don't use any local state and put everything into Redux. This attempts to solve the "reusable component communicating with others" issue, which by the way I don't think Redux solves well(there's tons of 3rd party libraries trying to deal with that). For this specific case, I think "global variable + event emitter" is a decent solution.
What about more complex state interactions? Well, for them I think the concepts Redux introduces are incredibly useful - not having to worry about your state's consistency is a huge help in debugging. Does Redux itself really deliver them 100%? Well, quite often a lot of your state changes will be coupled with side effects, ranging from animations to API calls. Without carefully designing your reducers, the side effects will quickly eat up any benefit - you may be stuck debugging "why doesn't my action creator pass the appropriate action to my trivial reducers". This is a point that Redux doesn't really handle - there's lots of middleware, addons and full-blown libraries trying to deal with the issue(e.g. redux-thunk, redux-saga, and so on).
My personal opinion is that the concepts that Redux tries to introduce are very useful to know and keep in mind when designing your system. Whether you should commit to Redux the library(and its accompanying middlewares and so on) is a different decision. I think I've learned a lot from studying Redux and thinking about the concepts it tries to introduce. However, all the benefits Redux provides depend heavily on the design of your actions and reducers. With a poor design, you are stuck adding more boilerplate for no gains. This is why I wouldn't use it in many of my projects - I don't think I have the experience to design my state management in such a way as to extract significant value from Redux, without being bogged down by the extra boilerplate.
- aidos 10y agoI love this comment. After a lot of evaluation of different js frameworks over the last year I reached the same place with Redux. The principal is sound; it's clean, simple, and incredibly easy to understand. Ultimately though, your logic can end up scattered about the codebase and I worry about what these codebases are going to look like in a year's time. With MobX you can take a cue from Redux and enumerate all your actions. You're then free to apply the same strictness as you have with Redux in terms of the actions and dataflow. When people compare Redux to MobX, the thing that is always missed is that MobX provides patterns for efficient calculated / aggregated state. There's no logic in there - it's just a way of transforming your raw state into a read-only structure more suitable for your views. I guess the situation we've got now is that there are a lot of people who have gone deep on the Redux approach. And really - the code looks like Redux, which is one of my major concerns. When everyone decides that it's hard to manage the sprawling logic of a big Redux app it's going to be very hard to transition to any other pattern.