You are viewing documentation for a previous version of this software.

Switch to the latest stable version.

Mutations

Learn how to update data with the useMutation hook


Now that we've learned how to fetch data from our backend with Apollo Client, the natural next step is to learn how to update that data with mutations. This article demonstrates how to send updates to your GraphQL server with the useMutation hook. You'll also learn how to update the Apollo Client cache after executing a mutation, and how to track loading and error states for a mutation.

Prerequisites

This article assumes you're familiar with building basic GraphQL mutations. If you need a refresher, we recommend that you read this guide.

This article also assumes that you've already set up Apollo Client and have wrapped your React app in an ApolloProvider component. Read our getting started guide if you need help with either of those steps.

To follow along with the examples below, open up our starter project and sample GraphQL server on CodeSandbox. You can view the completed version of the app here.

Executing a mutation

The useMutation React hook is the primary API for executing mutations in an Apollo application. To run a mutation, you first call useMutation within a React component and pass it a GraphQL string that represents the mutation. When your component renders, useMutation returns a tuple that includes:

  • A mutate function that you can call at any time to execute the mutation

  • An object with fields that represent the current status of the mutation's execution

Let's look at an example. First, we'll create a GraphQL mutation named ADD_TODO, which represents adding an item to a to-do list. Remember to wrap GraphQL strings in the gql function to parse them into query documents:

JavaScript
JavaScript
index.js(hooks)
1import gql from 'graphql-tag';
2import { useMutation } from '@apollo/react-hooks';
3
4const ADD_TODO = gql`
5  mutation AddTodo($type: String!) {
6    addTodo(type: $type) {
7      id
8      type
9    }
10  }
11`;
12

Next, we'll create a component named AddTodo that represents the submission form for the to-do list. Inside it, we'll pass our ADD_TODO mutation to the useMutation hook:

JavaScript
JavaScript
index.js(hooks)
1function AddTodo() {
2  let input;
3  const [addTodo, { data }] = useMutation(ADD_TODO);
4
5  return (
6    <div>
7      <form
8        onSubmit={e => {
9          e.preventDefault();
10          addTodo({ variables: { type: input.value } });
11          input.value = '';
12        }}
13      >
14        <input
15          ref={node => {
16            input = node;
17          }}
18        />
19        <button type="submit">Add Todo</button>
20      </form>
21    </div>
22  );
23}

Calling the mutate function

The useMutation hook does not automatically execute the mutation you pass it when the component renders. Instead, it returns a tuple with a mutate function in its first position (which we assign to addTodo in the example above). You then call the mutate function at any time to instruct Apollo Client to execute the mutation. In the example above, we call addTodo when the user submits the form.

Providing options

Both useMutation itself and the mutate function accept options that are described in the API reference. Any options you provide to a mutate function override corresponding options you previously provided to useMutation. In the example above, we provide the variables option to addTodo, which enables us to specify any GraphQL variables that the mutation requires.

Tracking mutation status

In addition to a mutate function, the useMutation hook returns an object that represents the current state of the mutation's execution. The fields of this object (fully documented in the API reference) include booleans that indicate whether the mutate function has been called yet, and whether the mutation's result is currently loading.

Updating the cache after a mutation

When you execute a mutation, you modify back-end data. If that data is also present in your Apollo Client cache, you might need to update your cache to reflect the result of the mutation. This depends on whether the mutation updates a single existing entity.

Updating a single existing entity

If a mutation updates a single existing entity, Apollo Client can automatically update that entity's value in its cache when the mutation returns. To do so, the mutation must return the id of the modified entity, along with the values of the fields that were modified. Conveniently, mutations do this by default in Apollo Client.

Let's look at an example that enables us to modify the value of any existing item in our to-do list:

JavaScript
JavaScript
(hooks)
1const UPDATE_TODO = gql`
2  mutation UpdateTodo($id: String!, $type: String!) {
3    updateTodo(id: $id, type: $type) {
4      id
5      type
6    }
7  }
8`;
9
10function Todos() {
11  const { loading, error, data } = useQuery(GET_TODOS);
12  const [updateTodo] = useMutation(UPDATE_TODO);
13
14  if (loading) return <p>Loading...</p>;
15  if (error) return <p>Error :(</p>;
16
17  return data.todos.map(({ id, type }) => {
18    let input;
19
20    return (
21      <div key={id}>
22        <p>{type}</p>
23        <form
24          onSubmit={e => {
25            e.preventDefault();
26            updateTodo({ variables: { id, type: input.value } });
27
28            input.value = '';
29          }}
30        >
31          <input
32            ref={node => {
33              input = node;
34            }}
35          />
36          <button type="submit">Update Todo</button>
37        </form>
38      </div>
39    );
40  });
41}