Odyssey

Client-side GraphQL with React & Apollo
beta

Feature overview and setupGraphQL basicsApollo ExplorerApollo ClientCodegenDefining a queryArgumentsThe useQuery hook with variablesIntroducing mutationsOur mutation in action
10. Our mutation in action
4m

Overview

Building our mutations in the Explorer is a great place to start, but now we need to bring the same functionality into our app. Let's jump back into the code and send off our mutation using a new hook!

In this lesson, we will:

  • Learn about the useMutation hook
  • Increment the number of views on a track when the page is visited
  • Talk about the Apollo Client cache

💻 Mutation in client-land

Let's revisit our goal: we want to update the number of views just before we navigate from the homepage to the track page. This navigation is happening inside our TrackCard component.

Inside the src/containers folder, let's open up the track-card.tsx file.

At the top, let's start by importing the @apollo/client package. We'll need the useMutation hook to send our mutation to our server. We also need to bring in gql from our __generated__ folder, because we'll be using that same function for our mutation.

import { useMutation } from "@apollo/client";
import { gql } from "../__generated__";

Next, let's make a new variable to hold our mutation called INCREMENT_TRACK_VIEWS, setting it to the gql function call adding backticks (`). Inside the backticks, we'll paste the mutation we built previously in Studio, and add a comment to explain what this mutation is for.

/**
* Mutation to increment a track's number of views
*/
const INCREMENT_TRACK_VIEWS = gql(`
mutation IncrementTrackViews($incrementTrackViewsId: ID!) {
incrementTrackViews(id: $incrementTrackViewsId) {
code
success
message
track {
id
numberOfViews
}
}
}
`);

🎣 The useMutation hook

Because this is a mutation and not a query, we won't be using the useQuery hook we're familiar with. Instead we'll switch to the useMutation hook.

Inside the TrackCard component, we'll start off by calling the hook. It takes in the mutation we set up earlier, INCREMENT_TRACK_VIEWS, as the first parameter.

The second parameter is an options object with a variables key. Here, we'll add the incrementTrackViewsId variable and set it to the id of the track we're navigating to. This id has already been destructured for us at the top from the track prop.

useMutation(INCREMENT_TRACK_VIEWS, {
variables: { incrementTrackViewsId: id },
});

Now, here's a twist: unlike with useQuery, calling useMutation doesn't actually execute the mutation automatically!

Instead, the useMutation hook returns an array with two elements, which we'll start to destructure here.

const [incrementTrackViews] = useMutation(INCREMENT_TRACK_VIEWS, {
variables: { incrementTrackViewsId: id },
});

The first element is the mutate function we'll use to actually run the mutation later on. We'll call it incrementTrackViews. The second element is an object with information about the mutation: loading, error and data. This component doesn't need it, so we don't have to extract it.

We've added a new operation, so we need to regenerate our types for our frontend. Run the following command in the root directory.

npm run generate

👆🏽Setting up the onClick

When do we want to run our mutate function? When the user clicks on the card!

Let's add an onClick prop to the CardContainer component and configure it to call our mutate function, incrementTrackViews.

<CardContainer
to={`/track/${id}`}
onClick={() => incrementTrackViews()}
>

1️⃣ One more thing…

One last thing—let's add a console log to check the mutation response when it's completed.

To do this, let's go back to where we set up our useMutation hook and add another property to our options object. The onCompleted property is a callback function that will run when the mutation successfully completes, and it has access to the response that comes back. We'll log the response to the browser console.

const [incrementTrackViews] = useMutation(INCREMENT_TRACK_VIEWS, {
variables: { incrementTrackViewsId: id },
// to observe what the mutation response returns
onCompleted: (data) => {
console.log(data);
},
});

Our client app is ready to send off this mutation to the server! Let's see the results of our journey in the last lesson!

👀 Seeing the results

Let's see what our app looks like now!

Make sure your app is still running, or restart it by opening a terminal and running npm start. Then, we'll open up http://localhost:3000 in the browser.

We see all of the tracks on the homepage. Now let's click on the second track, and we should see the number of views here.

If we go back to the homepage and click on the track again, we now see that the number of views has gone up! Awesome!

Note: Keep in mind your number of views might differ from the video! To check if your mutation succeeded, open up your browser's Developer Tools and find the console.log message we set up earlier.

Task!

Now if you've got quick eyes (or a slow internet connection 🐌 ) you might notice something here. In fact, let's open up the developer tools console, and slow this down with video magic so we can see what exactly is going on.

Did you see that? The page loaded instantly with all the track data, then after a brief moment, the number of views changed from 2 to 3! And we see the console log we set up earlier pop up here. That means our mutation was completed after the page was loaded. So how were we seeing everything on the page with no errors before? And how did it update on this page even though we ran the mutation on the previous page?

🗳️ Apollo Client cache

That's thanks to the Apollo Client cache!

When we used the useQuery hook with variables, we saw how fast our track was shown on the page if we had already clicked on it before. That was because it was loaded from the cache, which means we didn't send unnecessary queries to our GraphQL API.

Similarly, we're still getting our page loaded from cache while our mutation is sent off to our API. Once it returns successfully, we get back our updated value for numberOfViews. Apollo Client is doing the work behind the scenes to look at the id of this track, search for it in the cache, and update its numberOfViews field. When the cache updates, so does the UI. Thanks Apollo Client!

Doodle showing Apollo Client cache process

Practice

How do we see the number of views for a track update while we're on the page?
Sending a mutation client-side
We use hooks to send requests to our GraphQL API from a React client. To send a mutation, we use the
 
 hook. This returns an 
 
, where the first element is the
 
 used to trigger the mutation. The second element is an object with more information about the mutation, such as loading, error and 
 
. This hook takes in a
 
 as the first parameter. It also takes in an 
 
object as the second parameter, where properties like 
 
are set.

Drag items from this box to the blanks above

  • integer

  • options

  • GraphQL operation

  • useMutation

  • array

  • values

  • useGqlQuery

  • useQuery

  • mutate function

  • variables

  • arguments

  • data

To pick up a draggable item, press the space bar. While dragging, use the arrow keys to move the item. Press space again to drop the item in its new position, or press escape to cancel.
Which of these are differences between the useQuery and useMutation hooks?
Code Challenge!

Use the useMutation hook to send the ASSIGN_SPACESHIP_MUTATION mutation to the server. It takes two variables: spaceshipId and missionId. Destructure the mutate function (call it assignSpaceship), as well as the loading, error and data properties from the return array of the hook.

Key takeaways

  • The useMutation hook accepts a mutation operation as its first parameter, and an options object with a variables key as its second parameter.
  • The useMutation hook does not execute the mutation automatically; instead, it returns an array. This array contains a mutate function, which we can call at a time of our choosing, as well as an object containing loading, error, and data properties.
  • The Apollo Client cache loads data that has already been fetched from the cache, leading to faster load time on the page and fewer unnecessary network calls!

🎉 And we're done!

Thanks so much for joining us for Client-side GraphQL with React & Apollo. We've now got a working application for aspiring catstronauts to use to explore the universe, and we can see how popular a track is with its number of views.

We'd love to hear your feedback. Let us know what you liked, didn't like, and what you'd like to see next on Odyssey!

Previous

Share your questions and comments about this lesson

This course is currently in

beta
. Your feedback helps us improve! If you're stuck or confused, let us know and we'll help you out. All comments are public and must follow the Apollo Code of Conduct. Note that comments that have been resolved or addressed may be removed.

You'll need a GitHub account to post below. Don't have one? Post in our Odyssey forum instead.

              mutations

              A GraphQL operation that modifies data on the server. It allows clients to perform create, update, or delete operations, altering the underlying data.

              Apollo Client

              An open-source library for client-side state management and GraphQL operation handling in Javascript/Typescript. Apollo Client is a fully featured caching GraphQL client with integrations for React, Angular, and more.

              mutation

              A GraphQL operation that modifies data on the server. It allows clients to perform create, update, or delete operations, altering the underlying data.

              mutation

              A GraphQL operation that modifies data on the server. It allows clients to perform create, update, or delete operations, altering the underlying data.

              variable

              A placeholder for dynamic values in an operation allowing parameterization and reusability in requests. Variables can be used to fill arguments or passed to directives.

              query GetUser($userId: ID!) {
              user(id: $userId) {
              firstName
              }
              }

              In the query above, userId is a variable. The variable and its type are declared in the operation signature, signified by a $. The type of variable is a non-nullable ID. A variable's type must match the type of any argument it's used for.

              mutation

              A GraphQL operation that modifies data on the server. It allows clients to perform create, update, or delete operations, altering the underlying data.

              mutation

              A GraphQL operation that modifies data on the server. It allows clients to perform create, update, or delete operations, altering the underlying data.

              mutation

              A GraphQL operation that modifies data on the server. It allows clients to perform create, update, or delete operations, altering the underlying data.

              query

              A request for specific data from a GraphQL server. Clients define the structure of the response, enabling precise and efficient data retrieval.

              mutation

              A GraphQL operation that modifies data on the server. It allows clients to perform create, update, or delete operations, altering the underlying data.

              variable

              A placeholder for dynamic values in an operation allowing parameterization and reusability in requests. Variables can be used to fill arguments or passed to directives.

              query GetUser($userId: ID!) {
              user(id: $userId) {
              firstName
              }
              }

              In the query above, userId is a variable. The variable and its type are declared in the operation signature, signified by a $. The type of variable is a non-nullable ID. A variable's type must match the type of any argument it's used for.

              mutation

              A GraphQL operation that modifies data on the server. It allows clients to perform create, update, or delete operations, altering the underlying data.

              mutation

              A GraphQL operation that modifies data on the server. It allows clients to perform create, update, or delete operations, altering the underlying data.

              mutation

              A GraphQL operation that modifies data on the server. It allows clients to perform create, update, or delete operations, altering the underlying data.

              operation

              A single query, mutation, or subscription that clients send to a GraphQL server to request or manipulate data.

              mutation

              A GraphQL operation that modifies data on the server. It allows clients to perform create, update, or delete operations, altering the underlying data.

              mutation

              A GraphQL operation that modifies data on the server. It allows clients to perform create, update, or delete operations, altering the underlying data.

              mutation

              A GraphQL operation that modifies data on the server. It allows clients to perform create, update, or delete operations, altering the underlying data.

              mutation

              A GraphQL operation that modifies data on the server. It allows clients to perform create, update, or delete operations, altering the underlying data.

              mutation

              A GraphQL operation that modifies data on the server. It allows clients to perform create, update, or delete operations, altering the underlying data.

              Apollo Client

              An open-source library for client-side state management and GraphQL operation handling in Javascript/Typescript. Apollo Client is a fully featured caching GraphQL client with integrations for React, Angular, and more.

              variables

              A placeholder for dynamic values in an operation allowing parameterization and reusability in requests. Variables can be used to fill arguments or passed to directives.

              query GetUser($userId: ID!) {
              user(id: $userId) {
              firstName
              }
              }

              In the query above, userId is a variable. The variable and its type are declared in the operation signature, signified by a $. The type of variable is a non-nullable ID. A variable's type must match the type of any argument it's used for.

              GraphQL

              An open-source query language and specification for APIs that enables clients to request specific data, promoting efficiency and flexibility in data retrieval.

              mutation

              A GraphQL operation that modifies data on the server. It allows clients to perform create, update, or delete operations, altering the underlying data.

              Apollo Client

              An open-source library for client-side state management and GraphQL operation handling in Javascript/Typescript. Apollo Client is a fully featured caching GraphQL client with integrations for React, Angular, and more.

              field

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              Apollo Client

              An open-source library for client-side state management and GraphQL operation handling in Javascript/Typescript. Apollo Client is a fully featured caching GraphQL client with integrations for React, Angular, and more.

              mutation

              A GraphQL operation that modifies data on the server. It allows clients to perform create, update, or delete operations, altering the underlying data.

              operation

              A single query, mutation, or subscription that clients send to a GraphQL server to request or manipulate data.

              mutation

              A GraphQL operation that modifies data on the server. It allows clients to perform create, update, or delete operations, altering the underlying data.

              Apollo Client

              An open-source library for client-side state management and GraphQL operation handling in Javascript/Typescript. Apollo Client is a fully featured caching GraphQL client with integrations for React, Angular, and more.

              GraphQL

              An open-source query language and specification for APIs that enables clients to request specific data, promoting efficiency and flexibility in data retrieval.

              Odyssey

              Apollo's official learning platform, featuring interactive tutorials, videos, code challenges, and certifications.

              NEW COURSE ALERT

              Introducing Apollo Connectors

              Connectors are the new and easy way to get started with GraphQL, using existing REST APIs.

              Say goodbye to GraphQL servers and resolvers—now, everything happens in the schema!

              Take the course