How to make a GraphQL Mutation from a React component
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'
andwatchQuery: '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).
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