I was toying with the idea of using mergeProps in lieu of mapStateToProps and mapDispatchToProps today and came across behavior I don't fully understand.
Currently the defaultMapDispatchToProps function will return the dispatch argument.
var defaultMapDispatchToProps = function defaultMapDispatchToProps(dispatch) {
return { dispatch: dispatch };
};
and the defaultMapStateToProps function returns an empty object
var defaultMapStateToProps = function defaultMapStateToProps(state) {
return {};
}; // eslint-disable-line no-unused-vars
Why not have defaultMapStateToProps return {state:state}? This would allow someone to do:
const mergeProps = (stateProps, dispatchProps, ownProps) => {
const { state } = stateProps;
const { dispatch } = dispatchProps;
return {
...ownProps,
mySelector: importedSelector(state),
myAction: dispatch(importedAction(importedSelector(state).someProp))
}
}
@connect(undefined, undefined, mergeProps)
The default allows connect to opt out of subscribing to store changes. Useful when you just need to dispatch. Returning the whole state would be a huge performance deoptimization and is recommended against.
To follow on with that: connect's behavior is to take the object returned by mapState, and every time any of the fields in that object changes, re-render the child component. In this case, the state field would have changed every time the store was updated, and therefore always cause those components to re-render.
I would flip around Jim's phrasing a bit. mapState is an opt-in approach. You declare that a component should actually be subscribed to the store, and what data that component needs to extract.
Thanks for the clear explanation, definitely a sensible approach.
Most helpful comment
The default allows connect to opt out of subscribing to store changes. Useful when you just need to dispatch. Returning the whole state would be a huge performance deoptimization and is recommended against.