Combining Redux & Apollo Containers

June 11, 2018 0 Comments

Combining Redux & Apollo Containers

 

 

Redux and Apollo are popular implementations of Flux architecture and GraphQL respectively. A common pattern is to make a GraphQL query with data from the Redux state. If the state value changes, Apollo should re-run the query and the new data should be reflected in the UI.

As an example, let’s consider a restaurant website with a rotating menu populated from the server; when a visitor selects a date, the menu should update.

First, let’s create the dispatcher and pass it to the contained component.

function mapDispatchToProps(dispatch: Dispatch): DispatchProps { return { selectDate: (date) => { dispatch({ type: SELECT_MENU_DATE_ACTION_TYPE, menuDate: date }); } }; }

Update the state with the new menuDate when the contained component dispatches the action.

export function updateState(state: State, action: MenuAction): State { switch (action.type) { case SELECT_MENU_DATE_ACTION_TYPE: return { ...state, menuDate: action.menuDate }; default: return state; } }

Now that the Redux state is updated, we need to use the new menuDate in our GraphQL query.

function mapStateToProps(state: State): StateProps { return { date: state.menuDate } } const connectRedux = connect(mapStateToProps);

Set up the GraphQL query to take in a variable, $date.

const query = gql` query Menu($date: String!) { menu(date: $date) { items { name priceInCents } } } `;

Map the menuDate from the Redux state to the $date GraphQL variable.

function mapOwnPropsToOptions(ownProps: ApolloOwnProps) { return { variables: { date: ownProps.date.toISOString() } }; }

Then connect the query with the map from the query result to the contained component’s props, MenuProps.

function mapQueryResultToContainedProps(opts: OptionProps<ApolloOwnProps, ApolloQueryResult>): MenuProps { if (!opts.data || opts.data.loading || !opts.data.menu) { return { items: [] }; } return { items: opts.data.menu.items }; } const connectApollo = graphql<any, ApolloQueryResult, { date: string }, MenuProps>( query, { options: mapOwnPropsToOptions, props: mapQueryResultToContainedProps } );

Now we can feed the Redux output into Apollo, and then the final output to the contained component.

export const Menu = connectRedux(connectApollo(MenuComponent));

At this point, you should be able to see the Redux state changes triggering Apollo queries as expected. See this GitHub project for the complete code example.


Tag cloud