useMutation composable. It provides methods to trigger mutations and tracks their state reactively.
Signature
function useMutation<TData, TError, TVariables, TContext>(
options: UseMutationOptions<TData, TError, TVariables, TContext>,
queryClient?: QueryClient,
): UseMutationReturnType<TData, TError, TVariables, TContext>
Parameters
Configuration options for the mutation. Can be a reactive ref or getter function.
Show properties
Show properties
The function that performs the mutation. Can be a ref.
Called before mutation executes. Useful for optimistic updates. Can be a ref.
Called when mutation succeeds. Can be a ref.
Called when mutation fails. Can be a ref.
onSettled
MaybeRefDeep<(data: TData | undefined, error: TError | null, variables: TVariables, context: TContext | undefined) => void>
Called when mutation completes (success or error). Can be a ref.
Number of retry attempts or boolean to enable/disable retries. Can be a ref.
Delay between retry attempts. Can be a ref.
Throw errors instead of setting error state. Can be a ref.
Return state in shallow refs (improves performance if state doesn’t need deep reactivity).
Custom QueryClient instance. If not provided, uses the client from context.
Returns
Reactive refs containing mutation state and methods.
Show properties
Show properties
Trigger the mutation. Fire-and-forget style (doesn’t return a promise).
Trigger the mutation and return a promise.
The mutation result data.
The error object if the mutation failed.
true when the mutation is currently executing.true when the mutation has succeeded.true when the mutation has failed.true when the mutation is idle (not executing).The current status of the mutation.
The variables passed to the mutation.
Reset the mutation state to initial values.
Type Parameters
TData- Type of data returned by the mutationTError- Type of error (defaults toDefaultError)TVariables- Type of variables passed to the mutation (defaults tovoid)TContext- Type of context returned byonMutate(defaults tounknown)
Examples
Basic Usage
<script setup>
import { useMutation, useQueryClient } from '@tanstack/vue-query'
const queryClient = useQueryClient()
const { mutate, isPending, isError, error } = useMutation({
mutationFn: async (newTodo) => {
const res = await fetch('/api/todos', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(newTodo),
})
return res.json()
},
onSuccess: () => {
// Invalidate and refetch
queryClient.invalidateQueries({ queryKey: ['todos'] })
},
})
const addTodo = () => {
mutate({ title: 'New Todo', completed: false })
}
</script>
<template>
<div>
<button @click="addTodo" :disabled="isPending">
{{ isPending ? 'Adding...' : 'Add Todo' }}
</button>
<div v-if="isError">Error: {{ error.message }}</div>
</div>
</template>
With TypeScript
<script setup lang="ts">
import { useMutation } from '@tanstack/vue-query'
interface Todo {
id: number
title: string
completed: boolean
}
interface CreateTodoVariables {
title: string
completed: boolean
}
const { mutate } = useMutation({
mutationFn: async (variables: CreateTodoVariables): Promise<Todo> => {
const res = await fetch('/api/todos', {
method: 'POST',
body: JSON.stringify(variables),
})
return res.json()
},
})
// Type-safe mutation call
mutate({ title: 'Learn Vue Query', completed: false })
</script>
Optimistic Updates
<script setup>
import { useMutation, useQueryClient } from '@tanstack/vue-query'
const queryClient = useQueryClient()
const { mutate } = useMutation({
mutationFn: updateTodo,
onMutate: async (newTodo) => {
// Cancel outgoing refetches
await queryClient.cancelQueries({ queryKey: ['todos'] })
// Snapshot previous value
const previousTodos = queryClient.getQueryData(['todos'])
// Optimistically update cache
queryClient.setQueryData(['todos'], (old) => {
return old.map(todo =>
todo.id === newTodo.id ? newTodo : todo
)
})
// Return context with snapshot
return { previousTodos }
},
onError: (err, newTodo, context) => {
// Rollback on error
queryClient.setQueryData(['todos'], context.previousTodos)
},
onSettled: () => {
// Always refetch after error or success
queryClient.invalidateQueries({ queryKey: ['todos'] })
},
})
</script>
Using mutateAsync
<script setup>
import { useMutation } from '@tanstack/vue-query'
import { ref } from 'vue'
const { mutateAsync, isPending } = useMutation({
mutationFn: createTodo,
})
const handleSubmit = async () => {
try {
const newTodo = await mutateAsync({ title: 'New Todo' })
console.log('Created todo:', newTodo)
// Navigate or show success message
} catch (error) {
console.error('Failed to create todo:', error)
}
}
</script>
Per-Mutation Callbacks
<script setup>
import { useMutation } from '@tanstack/vue-query'
const { mutate } = useMutation({
mutationFn: createTodo,
})
// Pass callbacks per mutation call
const handleCreate = () => {
mutate(
{ title: 'New Todo' },
{
onSuccess: (data) => {
console.log('Created:', data)
},
onError: (error) => {
console.error('Failed:', error)
},
}
)
}
</script>
Reactive Mutation Options
<script setup>
import { ref, computed } from 'vue'
import { useMutation } from '@tanstack/vue-query'
const retryCount = ref(3)
// Options can be reactive
const mutationOptions = computed(() => ({
mutationFn: createTodo,
retry: retryCount.value,
}))
const { mutate } = useMutation(mutationOptions)
</script>
Reset Mutation State
<script setup>
import { useMutation } from '@tanstack/vue-query'
const { mutate, reset, isSuccess, error } = useMutation({
mutationFn: createTodo,
})
const handleCreate = () => {
// Reset previous state before new mutation
reset()
mutate({ title: 'New Todo' })
}
</script>
Related
- useQuery - For fetching data