Reputation: 1929
This tutorial by Dan Abramov suggests that the advantage to using selectors that act on global state (rather than a slice of state) is that they allow containers to be decoupled from knowledge of the state structure.
If that's the case, shouldn't we also avoid directly mapping state values to props, and use selectors instead? Otherwise, our containers must still know about where those values exist in the state tree.
To illustrate using an example...
Directly maps a nested state value to a prop:
const mapStateToProps = (state) => ({
isModalVisible: state.modal.isVisible,
});
VS
Has no knowledge of state structure. Gets value using isModalVisible()
selector:
const mapStateToProps = (state) => ({
isModalVisible: isModalVisible(state),
});
However, the problem with the latter approach is that for each value in the state tree, we have to write a selector. This seems like a lot of boilerplate code just to select a simple value. Is this considered best practice?
Upvotes: 10
Views: 566
Reputation: 1643
Do not mix the local state with the global state (redux store). You can have both on a component but the local state should not depend on global state.
This is due to the following reasons:
Upvotes: 1
Reputation: 601
The answer for your question is: "it depends"
Do you have a tiny app?
Maybe avoid using redux at all and stick to react components state.
Do you have a small app?
Writing a bunch of selectors is a lot of boilerplate just like you said. Avoid writing them and stick to simply mapping, using mapStateToProps
.
Medium to large apps?
This is where selectors and memoized selectors pay-off. You'll find yourself checking if modals is visible in many components. Currently in your state modal is under state.modal.visible
. But tomorrow a modal might be a part of a parent modal, you'll have to change all mapping in all your components to state.parentModal.modal.visible
. You can see how this can turn badly right?
The pros of selectors:
mapPropsToState
function.Pros of Memoized selectors:
Cons
Hope it answers your question.
Upvotes: 7
Reputation: 400
mapStateToProps
is the selector. You don't need to write a separate function for isModalVisible
necessarily. The idea is mapStateToProps
is the only function that needs to know the structure of the global state. You can break down that function if you want, especially as the subs-selectors get more complex, but if all you're doing is selecting a simple value, there's no need to do so.
As a result, the container component doesn't know the state structure. It just knows the structure of the value returned by mapStateToProps
. Your two examples are functionally equivalent, as it relates to the question "Should containers know the state structure?". Because in both cases, the answer is "They don't."
Upvotes: 3
Reputation: 3889
Responding to your last comment, yes, it's recommended to write selectors for all values in the tree, even for simple, non-derived value.
Several reasons to do so:
As I mentioned in the comments, once you are using selectors for all the values, you can modify the tree structure as you like and then you only need to modify selectors accordingly. Otherwise you and your co-developer will have to modify every direct mapping mannually, even it's non-derived data.
Decoupling values between different levels in the tree. Like you said, when you have a global-level selector depends on a slice-level selector, e.g. price
inside product
. When you put product onto somewhere else in the tree, just modify the product
selector, and all you global-level selector price
will still be fine. I'm not sure Dan mentioned in his tutorial, check this library reselect. It shows the idea between levels.
Efficiency when fetching computed data.
Ofc if you are doing a small project or retrieving simple non-derived values from the tree, you can use direct mapping. But keep in mind applying selectors widely makes your code scalable.
Upvotes: 3