There are a couple of things I’ve struggled a lot with in working out best practices for React/Redux:
- How to actually implement the advice to use selectors everywhere
- How to get access to state when I need it
These two things are related, because selectors in general need access to the whole state tree (I think).
So I use three basic techniques:
1. To pass state to react components, I use react-redux, where the mapStateToProps function has access to the global state.
2. To provide state to reducers, I use redux-thunk, which lets me use state-aware action creators and thereby add all required state to the action payloads.
3. Alternatively, I use the third argument to redux-react’s connect() function, mergeProps, which lets me access both global state and component properties and pass them to action creators (and through actions, to the reducers).
Here’s a very basic sketch of how these three approaches look:
// A redux-thunk action creator that uses the getState() // function to pass state to selectors export function actionCreator1(someState, someProps) { return function (dispatch, getState) { someMoreState = selector3(getState()); dispatch(action1(someState, someMoreState)); }; } // A normal action creator that just gets precalculated state export actionCreator2 = (someState) => ({ someState, }); // A redux-react function that can use global state tree to call selectors const mapStateToProps = (state, ownProps) => ({ state1: selector1(state), state2: selector2(state), }); const mapDispatchToProps = (dispatch) => ({ dispatch }); const mergeProps = (stateProps, dispatchProps, ownProps) => { return { ...ownProps, ...stateProps, // using stateProps to pass state to action creators action1: () => dispatch(actionCreator1(stateProps.state1, ownProps)), action2: () => dispatch(actionCreator2(stateProps.state2)), } }; export const Container = connect( mapStateToProps, mapDispatchToProps, mergeProps )(Component);
Using these approaches, I can get access to whatever state I need, and therefore use selectors all over the place. I suspect this also lets me get away with a pretty suboptimal state tree and just paper over the gaps with global state and heavy-weight selectors. But I suspect that even with a great state tree shape and great selector design, these techniques are still going to be necessary. Maybe just less so.