Client-Side Mutations
Mutations on the client side let you modify data on the server and update your application's state. Apollo Client makes this straightforward with the useMutation hook.
Basic Mutations
The useMutation hook returns a function that triggers the mutation and the result state:
import { useMutation, gql } from '@apollo/client';
const CREATE_USER = gql`
mutation CreateUser($input: CreateUserInput!) {
createUser(input: $input) {
id
name
email
}
}
`;
function CreateUserForm() {
const [createUser, { loading, error, data }] = useMutation(CREATE_USER);
const handleSubmit = async (e) => {
e.preventDefault();
await createUser({
variables: {
input: {
name: 'Charlie',
email: 'charlie@example.com',
},
},
});
};
return (
<form onSubmit={handleSubmit}>
{loading && <p>Creating user...</p>}
{error && <p>Error: {error.message}</p>}
{data && <p>User created: {data.createUser.name}</p>}
<button type="submit">Create User</button>
</form>
);
}
The mutation function is lazy - it only executes when you call it. The result contains loading, error, and data states.
Updating the Cache
After a mutation, you often need to update the cache so your UI reflects the changes. Apollo Client provides the update function for this:
const GET_USERS = gql`
query GetUsers {
users {
id
name
email
}
}
`;
const CREATE_USER = gql`
mutation CreateUser($input: CreateUserInput!) {
createUser(input: $input) {
id
name
email
}
}
`;
function CreateUserForm() {
const [createUser] = useMutation(CREATE_USER, {
update(cache, { data: { createUser } }) {
// Read the current cache
const { users } = cache.readQuery({ query: GET_USERS });
// Write the new user to the cache
cache.writeQuery({
query: GET_USERS,
data: { users: [...users, createUser] },
});
},
});
}
The update function lets you manually update the cache after a mutation. This keeps your UI in sync with the server.
Refetching Queries
Instead of manually updating the cache, you can refetch queries after a mutation:
function CreateUserForm() {
const [createUser] = useMutation(CREATE_USER, {
refetchQueries: [{ query: GET_USERS }],
});
// Or just refetch specific queries
const [deleteUser] = useMutation(DELETE_USER, {
refetchQueries: ['GetUsers'], // Can use query names
});
}
refetchQueries is simpler but makes an extra network request. Use it when the cache update logic is complex.
Optimistic Updates
Optimistic updates make your UI feel faster by immediately updating the cache before the server responds:
const [createUser] = useMutation(CREATE_USER, {
optimisticResponse: {
createUser: {
__typename: 'User',
id: 'temp-id',
name: 'Charlie',
email: 'charlie@example.com',
},
},
update(cache, { data: { createUser } }) {
const { users } = cache.readQuery({ query: GET_USERS });
cache.writeQuery({
query: GET_USERS,
data: { users: [...users, createUser] },
});
},
});
If the mutation fails, Apollo automatically rolls back the optimistic update. This gives users instant feedback while maintaining data integrity.