Mutations
Mutations Basics
villus offers a useMutation
function that is very similar to its querying counterpart but with few distinct differences:
- It does not accept a
variables
option. - It does not execute automatically, you have to explicitly call
execute
. - Cache policies do not apply to mutations as mutations represent user actions and will always use
network-only
policy.
Here is an example of the useMutation
function:
vue<template>
<div>
<div v-if="data">
<p>{{ data.likePost.message }}</p>
</div>
<button @click="execute()">Submit</button>
</div>
</template>
<script setup>
import { useMutation } from 'villus';
const LikePost = `
mutation {
likePost (id: 123) {
message
}
}
`;
const { data, execute } = useMutation(LikePost);
</script>
Passing Variables
Since the useMutation
function does not accept a variables
property you can pass them to the execute
function:
vue<script setup>
const LikePost = `
mutation LikePost ($id: ID!) {
likePost (id: $id) {
message
}
}
`;
const { data, execute } = useMutation(LikePost);
function onSubmit() {
const variables = {
id: 123,
};
execute(variables);
}
</script>
Clearing Tagged Queries Cache
To clear tagged queries’ cache, you can specify a clearCacheTags
option when calling useMutation
composable:
vue<script setup>
const CreatePost = `
mutation CreatePost ($title: String!) {
createPost (title: $title) {
id
}
}
`;
const GetPosts = `
query GetPosts {
posts {
id
title
}
}
`;
const { data } = useQuery(GetPosts, {
tags: ['all_posts'],
});
const { execute } = useMutation(CreatePost, {
clearCacheTags: ['all_posts'],
});
function onSubmit() {
execute({
title: 'hello there',
});
}
</script>
This will clear all the cache entries for any queries tagged with all_posts
when using useQuery
. The next time they are fetched they will go straight to the network and fetch the fresh data from the server.
Refetching queries after a mutation
Aside from clearing the cache for tagged queries, you can also refetch them. By specifying refetchTags
option when calling useMutation
composable:
vue<script setup>
const CreatePost = `
mutation CreatePost ($title: String!) {
createPost (title: $title) {
id
}
}
`;
const GetPosts = `
query GetPosts {
posts {
id
title
}
}
`;
const { data } = useQuery(GetPosts, {
tags: ['all_posts'],
});
const { execute } = useMutation(CreatePost, {
refetchTags: ['all_posts'],
});
function onSubmit() {
execute({
title: 'hello there',
});
}
</script>
After the mutation execution completes, it will trigger a refetch for all queries tagged with all_posts
tag. Note that refetchTags
also clear the cache if present for those tagged queries, so the refetch will always override the network policy and the cached results.
Handling Errors
You can handle errors by either grabbing the error
ref returned from the useMutation
function or by checking the result of the execute
promise, the latter is preferable as it makes more sense in most situations. The execute
function doesn’t throw and collects all encountered errors into a CombinedError
instance that contains any GraphQL or network errors encountered.
vue<script setup>
const LikePost = `
mutation LikePost ($id: ID!) {
likePost (id: $id) {
message
}
}
`;
const { data, execute } = useMutation(LikePost);
const variables = {
id: 123,
};
function onSubmit() {
execute(variables).then(result => {
if (result.error) {
// Do something
}
});
}
</script>
Event hooks
useMutation returns event hooks allowing you to execute code when a specific event occurs.
onData
This is called whenever a new result is available.
vue<script setup>
import { useMutation } from 'villus';
const { data, execute } = useMutation(LikePost, {
onData: (data) => {
// Do something
console.log(data)
},
});
</script>
onError
It is triggered when an error occurs.
vue<script setup>
import { useMutation } from 'villus';
const { data, execute } = useMutation(LikePost, {
onError: (error) => {
// Handle the error
console.log(error)
},
});
</script>
There are more things you can do with mutations, like displaying progress for users. Check the API documentation for useMutation.