4 ms·
Hi, I'm a Redux maintainer, and I'd like to clarify a few things. First, your points about `dispatch` and `context` are specifically about the React-Redux bind
by acemarke 8y ago
Hi, I'm a Redux maintainer, and I'd like to clarify a few things.
First, your points about `dispatch` and `context` are specifically about the React-Redux bindings, not the Redux core itself. React-Redux is specifically intended to act as an abstraction layer so that your own components are "unaware" of Redux, which keeps them more reusable and more testable. It also saves you from needing to write store subscription handling every time you want to make use of data from the store. My "Redux Fundamentals" workshop slides [0] show examples of what it would look like to hand-write store subscription code all throughout your UI, and it would be a pain.
If you _really_ want to, there's nothing stopping you from importing the store globally across your application and using it, but that misses out on the benefits of React-Redux, and also ties you to that one specific store instance.
Second, you can absolutely do async logic without any middleware. However, one of the key design points of Redux was to allow users to choose which approach they want to use to handle async logic, without limiting users to whatever was built in to the core. I discussed this in my "Redux Ecosystem" talk at ReactBoston last year [1].
You can certainly do async logic without any special middleware - just `connect()(MyComponent)`, throw in a `setTimeout`, and call `this.props.dispatch()`. The point of `redux-thunk`, the most common async middleware, is that it provides a generic way to move async logic outside of your UI and make it reusable [2].
Finally, the "dispatching an action === calling a function" comparison can be true, but only if you're using Redux with a limited mental approach and treating actions like "setters". If you start thinking about actions as more of an "event that occurred", then that leads to having multiple parts of your reducer logic independently respond to the same action and update their own pieces of state (which is an encouraged usage pattern). Justin Falcone had some good thoughts on this a while back [3], and I talked about this some in a fewmore of my blog posts [4] [5] [6].
[0] https://blog.isquaredsoftware.com/2018/06/redux-fundamentals-workshop-slides/ https://blog.isquaredsoftware.com/2018/06/redux-fundamentals...
[1] https://blog.isquaredsoftware.com/2017/09/presentation-might-need-redux-ecosystem/ https://blog.isquaredsoftware.com/2017/09/presentation-might...
[2] https://blog.isquaredsoftware.com/presentations/workshops/redux-fundamentals/side-effects.html#/4 https://blog.isquaredsoftware.com/presentations/workshops/re...
[3] https://medium.freecodecamp.org/whats-so-great-about-redux-ac16f1cc0f8b https://medium.freecodecamp.org/whats-so-great-about-redux-a...
[4] https://blog.isquaredsoftware.com/2017/01/idiomatic-redux-thoughts-on-thunks-sagas-abstraction-and-reusability/ https://blog.isquaredsoftware.com/2017/01/idiomatic-redux-th...
[5] https://blog.isquaredsoftware.com/2017/05/idiomatic-redux-tao-of-redux-part-2/ https://blog.isquaredsoftware.com/2017/05/idiomatic-redux-ta...
[6] https://blog.isquaredsoftware.com/2017/01/practical-redux-part-8-form-draft-data-management/#improving-the-pilot-deletion-logic https://blog.isquaredsoftware.com/2017/01/practical-redux-pa...
- strken 8y agoThis is all absolutely true! Redux and React-Redux, and their associated documentation make a lot of intelligent design tradeoffs that have a lot of thought put into them, and that's worthy of respect. "Overengineered" was too strong a term, and I shouldn't have used it. Sorry. However, some of the things that have been traded are default configuration that represents typical use, standardisation across the ecosystem, and brevity. I think that for a lot of use cases, these tradeoffs make React-Redux harder to use, and that as a whole they make it easier to cause significant architectural problems for a newer or less technical user. > If you _really_ want to, there's nothing stopping you from importing the store globally What I've taken to doing is exporting a dispatch function that calls the store's dispatch, not the store. I think this better captures the intention behind Flux than a higher-order component, without much cost, since dynamically swapping between stores doesn't seem common. > ...one of the key design points of Redux was to allow users to choose which approach they want to use to handle async logic... This power and choice, while allowing a lot of freedom, comes at the cost of a fragmented ecosystem. The Redux documentation page for async actions lists six different packages that can help. > the "dispatching an action === calling a function" comparison can be true, but only if you're using Redux with a limited mental approach and treating actions like "setters" I may not have explained that very well. Actions themselves make perfect sense from the perspective of a reducer, and clearly they must be dispatched, but they're a state management detail that the UI doesn't need to know about. Something similar to redux-action could be the default. I suppose my core problem with Redux/React-Redux is that I don't understand why a typical component in a typical app doesn't look like import { connect } from 'redux' import { deleteFoo } from '../actions' const FooList = ({ foos }) => { return foos.map(foo => <button onClick={() => deleteFoo(foo.id)}>Delete {foo.name}</button>) } export default connect(state => ({ foos: state.foos }))(FooList)
- acemarke 8y agoYeah, for a while it seemed like there was a new Redux side effects lib coming out every week. At this point, though, it's pretty much standardized on thunks for basic use cases, and either sagas or observables for more advanced use cases based on your preference of writing async logic. > What I've taken to doing is exporting a dispatch function that calls the store's dispatch, not the store. Not sure I follow that train of thought - could you point to an example? > Actions themselves make perfect sense from the perspective of a reducer, and clearly they must be dispatched, but they're a state management detail that the UI doesn't need to know about. Something similar to redux-action could be the default. This is why we recommend use of action creators, so that a component is just calling `this.props.doSomething()` without it "knowing" that a Redux action is actually being dispatched. Per your snippet there at the end: - `redux` and `react-redux` are deliberately separate packages, because the Redux core is 100% vanilla JS, and independent from React (in the same way that `react` and `react-dom` are separate packages - the core React logic is independent of the platform-specific reconcilers). So, `import {connect} from "redux"` wouldn't be appropriate. - The use of `deleteFoo()` that way assumes that it's pre-bound to a specific store instance, which limits the reusability of your logic, and also makes it a lot harder to test. `connect` abstracts away the question of "which store instance am I interacting with?", so that your components and logic are more testable and reusable. > Something similar to redux-action could be the default. For what it's worth, earlier this year I threw together a small `redux-starter-kit` package: https://github.com/markerikson/redux-starter-kit https://github.com/markerikson/redux-starter-kit . The goal behind it is to simplify some of the most common pain points around Redux: store setup (including thunks and devtools), writing immutable updates in reducers, and having to install multiple packages out of the box. The biggest thing I know it's still missing at this point is indeed something akin to `redux-actions` - see my notes at https://github.com/markerikson/redux-starter-kit/issues/17 https://github.com/markerikson/redux-starter-kit/issues/17 . I haven't had time to push it forward further, but I would seriously like to get some more eyes on it, see if there's any other use cases we should be covering, and then make it an official Redux-branded package and update our docs to recommend that people use it.