Redux, selectors, and access to state

There are a couple of things I’ve struggled a lot with in working out best practices for React/Redux:

  1. How to actually implement the advice to use selectors everywhere
  2. 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.