React Apollo

Why I had to do the same feature twice

Current module architecture shows why we do same work twice

Feature Explanation

Data Loading

const loadOneRestCall = () => async (dispatch) => {
  const data = await api.loadData();
  dispatch(setData(data));
}

...

export const loadEditOrderIfNecessary = (orderId) => async (dispatch, getState) => {
  if (!selectors.getComplexSelectorShouldLoad(getState(), orderId)) {
    return;
  }
  await Promise.all([
    dispatch(loadOneRestCall()),
    dispatch(loadSecondRestCall()),
  ]).then(() => {
    dispatch(setEditOrderFormLoaded());
  });
}
class EditOrderComponent extends React.PureComponent {
  componentDidMount() {
    this.props.dispatch(actions.loadEditOrderIfNecessary(this.props.orderId));
  }

  render() {
    if (this.props.loading) {
      return <Loader/>;
    }

    return (
     <Form data={this.props.data} />
    );
  }
}

const mapStateToProps = (state) => {
  return {
    data: editOrderSelector.getFormData(state),
    loading: editOrderSelector.isLoading(state),
  };
};

export const EditOrder = connect(mapStateToProps)(EditOrderComponent);

Calling the API

const EDIT_ORDER_QUERY = gql`
  query EditOrderQuery(orderId: ID!) {
    order(id: $orderId) {
      ...Order
    }
  }
`;

class EditOrderComponent extends React.PureComponent {
  render() {
    return (
      <Query query={EDIT_ORDER_QUERY} variables={{orderId: this.props.orderId}}>
        {(data, loading) => {
          if (loading) {
            return <Loader/>;
          }
          
          return (
            <Form data={data}/>
          );
        }}
      </Query>
    );
  }
}
Apollo Mutation pyramid

Updating the local state

...
render() {
  return (
    <Mutation onError={this.onError1} mutation={MUTATION1}>
      {(mutation1) => (
        <Mutation onError={this.onError2} mutation={MUTATION2}>
          {(mutation2) => (
            <Mutation onError={this.onError3} mutation={MUTATION3}>
              {(mutation3) => {
                return (
                  <View mutation1={mutation1}, mutation2={mutation2}, mutation3={mutation3}/>
                );
              }}
            </Mutation>
          )}
        </Mutation>
      )}
    </Mutation>
  );
}
Apollo manual cache update

E2E test

const cached = readQuery(cache, {query: QUERY, variables});

writeQuery(
  cache, 
  {
    query: QUERY,
    data: {
      orders: [order].concat(cached ? cached.orders : []),
    },
    variables,
  },
);
Mocking the query

Typescript and IDE support

Photo by Glenn Carstens-Peters on Unsplash

Redux benefits

How we are planning to reduce the amount of work

Start your journey into the world of React by learning these basics

Some statistics

Summary

Wix Engineering

Architecture, scaling, mobile and web development, management and more, written by our very own Wix engineers. https://www.wix.engineering/