How to determine mutation loading state with react-apollo graphql

rmarscher picture rmarscher · Sep 8, 2016 · Viewed 9k times · Source

2018 Update: Apollo Client 2.1 added a new Mutation component that adds the loading property back. See @robin-wieruch's answer below and the announcement here https://dev-blog.apollodata.com/introducing-react-apollo-2-1-c837cc23d926 Read on for the original question which now only applies to earlier versions of Apollo.


Using the current version of the graphql higher-order-component in react-apollo (v0.5.2), I don't see a documented way to inform my UI that a mutation is awaiting server response. I can see that earlier versions of the package would send a property indicating loading.

Queries still receive a loading property as documented here: http://dev.apollodata.com/react/queries.html#default-result-props

My application is also using redux, so I think one way to do it is to connect my component to redux and pass down a function property that will put my UI into a loading state. Then when rewriting my graphql mutation to a property, I can make calls to update the redux store.

Something roughly like this:

function Form({ handleSubmit, loading, handleChange, value }) {
  return (
    <form onSubmit={handleSubmit}>
      <input
        name="something"
        value={value}
        onChange={handleChange}
        disabled={loading}
      />
      <button type="submit" disabled={loading}>
        {loading ? 'Loading...' : 'Submit'}
      </button>
    </form>
  );
}

const withSubmit = graphql(
  gql`
    mutation submit($something : String) {
      submit(something : $something) {
        id
        something
      }
    }
  `, 
  {
    props: ({ ownProps, mutate }) => ({
      async handleSubmit() {
        ownProps.setLoading(true);
        try {
          const result = await mutate();
        } catch (err) {
          // @todo handle error here
        }
        ownProps.setLoading(false);
      },
    }),
  }
);

const withLoading = connect(
  (state) => ({ loading: state.loading }),
  (dispatch) => ({
    setLoading(loading) {
      dispatch(loadingAction(loading));
    },
  })
);

export default withLoading(withSubmit(Form));

I'm curious if there is a more idiomatic approach to informing the UI that the mutation is "in-flight." Thanks.

Answer

Robin Wieruch picture Robin Wieruch · Apr 22, 2018

Anyone who stumbles across this question, since Apollo Client 2.1 you have access to those properties in the Query and Mutation component's render props function.

import React from "react";
import { Mutation } from "react-apollo";
import gql from "graphql-tag";

const TOGGLE_TODO = gql`
  mutation ToggleTodo($id: Int!) {
    toggleTodo(id: $id) {
      id
      completed
    }
  }
`;

const Todo = ({ id, text }) => (
  <Mutation mutation={TOGGLE_TODO} variables={{ id }}>
    {(toggleTodo, { loading, error, data }) => (
      <div>
        <p onClick={toggleTodo}>
          {text}
        </p>
        {loading && <p>Loading...</p>}
        {error && <p>Error :( Please try again</p>}
      </div>
    )}
  </Mutation>
);

Note: Example code taken from the Apollo Client 2.1 release blog post.