w3resource

Mutations


In the previous tutorial, we've discussed how to fetch data from our backend with Apollo Client, sequentially, in this tutorial, we will learn how to update that data with mutations. This tutorial demonstrates how to send updates to your GraphQL server with the useMutation hook. We'll also learn how to update the Apollo Client cache after executing a mutation.

Prerequisites

This tutorial assumes you're familiar with building basic GraphQL mutations. If you need a refresher, we recommend you check our previous tutorials. We also assume that you've already set up Apollo Client and have wrapped your React app in an ApolloProvider component.

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:

//index.js
import gql from 'graphql-tag';
import {useMutation} from '@apollo/react-hooks';
const ADD_TODO = gql`
  mutation AddTodo($type: String!) {
    addTodo(type: $type) {
      id
      type
    }
  }
`;

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:

//index.js
function AddTodo() {
  let input;
  const [addTodo, { data }] = useMutation(ADD_TODO);

  return (
    <div>
      <form
        onSubmit={e => {
          e.preventDefault();
          addTodo({ variables: { type: input.value } });
          input.value = '';
        }}
      >
        <input
          ref={node => {
            input = node;
          }}
        />
        <button type="submit">Add Todo</button>
      </form>
    </div>
  );
}

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. Options provided to a mutate function override any options you previously provided in 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 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:

const UPDATE_TODO = gql`
  mutation UpdateTodo($id: String!, $type: String!) {
    updateTodo(id: $id, type: $type) {
      id
      type
    }
  }
`;

function Todos() {
  const { loading, error, data } = useQuery(GET_TODOS);
  const [updateTodo] = useMutation(UPDATE_TODO);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error :(</p>;

  return data.todos.map(({ id, type }) => {
    let input;

    return (
      <div key={id}>
        <p>{type}</p>
        <form
          onSubmit={e => {
            e.preventDefault();
            updateTodo({ variables: { id, type: input.value } });

            input.value = '';
          }}
        >
          <input
            ref={node => {
              input = node;
            }}
          />
          <button type="submit">Update Todo</button>
        </form>
      </div>
    );
  });
}

If you execute the UPDATE_TODO mutation using this component, the mutation returns both the id of the modified to-do item and the item's new type. Because Apollo Client caches entities by id, it knows how to automatically update the corresponding entity in its cache. The application's UI also updates immediately to reflect changes in the cache.

Previous: Queries
Next: Local state management