How to make a GraphQL Mutation from a React component

Peter Milne
Criteo R&D Blog
Published in
5 min readJun 10, 2024

This article is part of a series of six articles using React with the Apollo Client.

As a custom React component developer, I want to use GraphQL to mutate a business entity (Account in this example) and render it for the user.

I want to cache the mutation results and use “stale while revalidate” for this and subsequent queries.

I want any other component using the same data to be notified to re-render with updated data automatically.

Here is how to do it

To execute the mutation, use the useMutation hook from the ApolloClient package. This hook connects to the Apollo Client instance via the ApolloProvider context and removes the need to pass the Apollo Client instance as props, etc.

Render the result data using React techniques.

Apollo Client

The Apollo Client (Angular and React) provides methods and facilities for:

  • preparing queries gql('<query string here>')
  • parameterising mutations query Account($account: NewAccount!)
  • executing mutations useMutation<>()
  • caching and normalising results cache: new InMemoryCache()
  • Stale while revalidate fetchPolicy: 'cache-first' and watchQuery: 'cache-and-network

Using the Apollo Client abstracts front-end developers from the complexities of the above. It allows them to focus on the user interface implementation using only queries, mutations and subscriptions to access server-side data and commands. The front-end developer no longer needs to use axios or fetch to call REST APIs or deal with the inconsistencies of REST API dialects.

useMutation

Using the useMutation React hook is the primary API for executing mutations in a React application. It will ensure the mutation results are cached and normalised, and the fetch policies (in the client and the mutation) will ensure the cache is not stale.

To execute a mutation within a React component, call useMutation and pass it a GraphQL mutation compiled by the function gql. When the component is rendered, useMutation returns an array containing a function to execute the mutation and an object from the Apollo Client. The first element in the array is the query function, the second element is the object with the properties loading, error and data.

Code generation for TypeScript

The schema is the contract and is the source of truth.

One of the values of the schema-first approach is the easy generation of code from the schema. For front-end code, generating TypeScript types from the schema definitions is possible. (See GraphQL Codegen for Frontend)

Discussion

The solution uses:

  • Apollo Client instance — a single instance shared between ALL components via ApolloProvider and Apollo hooks.
  • Mutation definition — complied into AST exactly once
  • Code generation for TypeScript — for type-safe queries
  • Mutation execution — invoked in createAccount()
  • Watching for results — rendered in React and refreshed the cache via refreshQueries

Mutation definition and compilation

A best practice is to define and compile mutations exactly once.

In the front-end project, create a directory to contain mutation definitions; this can be the same file as Queries and Subscriptions. In this example, the directory graphql is a subdirectory under src and it contains query, mutation and subscription definitions; and types.ts generated from the schema (more on this later).

Example GraphQL directory in the frontend application

Here, each file is contributed by the domain or bounded context. Each operation in the file is compiled into an AST and stored in a public constant. Compilation is done only once when the page is loaded.

Example: accounts.graphql.ts

Line 63: The mutation string is compiled into an AST and stored in the public constant ACCOUNT_CREATE

Super Important — Each mutation should be named

Line 53: Name each mutation with a unique name; in this example, CreateAccount. The Apollo client uses this name to ensure that any component listening for this query's results is notified.

Mutate method — newAccount()

newAccount()

This example shows the AccountDetails component executing a mutation (CQRS command) when the user clicks the new account button.

Lines 31–49 Inside the newAccount function, the addAccount mutation function is called, passing in the variables for the mutation (lines 34–36).

Lines 37–39 Specify the refreshQueries. The Apollo client will automatically execute this array of queries when the mutation is complete. The refresh execution is done automatically; you do not need to code for it. It ensures that the client cache is not stale and that components that depend on those queries re-render automatically. In this example, ACCOUNTS_LIST is executed to show the new Account in the AccountsList component automatically.

Lines 40–47 process mutation results, handle loading and error states and navigation.

The mutation uses NewAccount, which defines the input object; NewAccountMutation, which defines the shape of the result; and NewAccountMutationVariables, which defines the query variables. These types are generated from GraphQL mutation definitions (see above) using graphql-codegen (see: GraphQL Codegen for Frontend)

Conclusion

GraphQL in React is made easy by using @apollo/client

Mutation results can be integrated with Reacts data binding for a seamless experience for the user.

The full source code is here

--

--

Peter Milne
Criteo R&D Blog

44 experience, Software Architect, Commercial helicopter pilot. Part-time mad scientist. Robotics Enthusiast. 3D printing geek