useMutation
1function useMutation<TData = unknown, TError = Error, TVariables = void, TOnMutateResult = unknown>(options: UseMutationOptions<TData, TError, TVariables, TOnMutateResult>, queryClient?: QueryClient): UseMutationReturnType<TData, TError, TVariables, TOnMutateResult>;定义于:packages/vue-query/src/useMutation.ts:237
与 查询 不同,修改 通常用于创建/更新/删除数据或执行服务端副作用。
useMutation 是用于此目的的组合式函数(composable)。
options 可以是普通对象、ref 或响应式 getter(() => ({ ... }))——若选项本身依赖其他响应式状态,请传入 getter。
类型参数
TData
TData = unknown
TError
TError = Error
TVariables
TVariables = void
TOnMutateResult
TOnMutateResult = unknown
参数
options
UseMutationOptions<TData, TError, TVariables, TOnMutateResult>
要使用的 UseMutationOptions —— 即所有可传给 useMutation 的配置项。
queryClient?
使用此参数可指定自定义的 QueryClient;否则将使用 VueQueryPlugin 提供的默认实例。
返回值
UseMutationReturnType<TData, TError, TVariables, TOnMutateResult>
mutate/mutateAsync 还支持以第二个参数形式传入每次调用专属的 onSuccess/onError/onSettled 回调函数,适用于在调用点触发副作用(例如导航),而无需将其耦合到共享的 修改 定义中。Hook 级回调(传给 options 的)会在每次 修改 时触发;而每次调用专属的回调仅对最近一次调用生效。
参见
mutationOptions 可用于在多个 useMutation 调用点之间共享这些选项,或通过其 mutationKey(例如配合 useMutationState)在其他位置查找该 修改。
示例
1<script setup lang="ts">2import { useMutation, useQueryClient } from '@tanstack/vue-query'34const queryClient = useQueryClient()56const addMutation = useMutation({7 mutationFn: addTodo,8 onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),9})1011function onAdd() {12 addMutation.mutate('Item', {13 onError: (error) => console.error('Failed to add item:', error),14 })15}16</script>17 18<template>19 <button @click="onAdd">Add</button>20</template>渲染 修改 自身的状态,而不仅是一次性触发它:
1<script setup lang="ts">2import { useMutation, useQueryClient } from '@tanstack/vue-query'34const queryClient = useQueryClient()56const addMutation = useMutation({7 mutationFn: addTodo,8 onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),9})10</script>11 12<template>13 <div v-if="addMutation.isPending.value">Adding todo...</div>14 <div v-else>15 <div v-if="addMutation.isError.value">An error occurred: {{ addMutation.error.value.message }}</div>16 <button @click="addMutation.mutate('Item')">Add</button>17 </div>18</template>通过 onMutate 实现乐观更新,并在 onError 时回滚:
1<script setup lang="ts">2import { useMutation, useQueryClient } from '@tanstack/vue-query'34const queryClient = useQueryClient()56const addMutation = useMutation({7 mutationFn: addTodo,8 onMutate: async (newTodo: string) => {9 await queryClient.cancelQueries({ queryKey: ['todos'] })10 const previousTodos = queryClient.getQueryData<Array<string>>(['todos'])1112 queryClient.setQueryData<Array<string>>(['todos'], (old) => [13 ...(old ?? []),14 newTodo,15 ])1617 // Passed to `onError` as `onMutateResult` if the mutation fails.18 return { previousTodos }19 },20 onError: (_err, _newTodo, onMutateResult) => {21 queryClient.setQueryData(['todos'], onMutateResult?.previousTodos)22 },23 onSettled: () => {24 queryClient.invalidateQueries({ queryKey: ['todos'] })25 },26})27</script>28 29<template>30 <button @click="addMutation.mutate('Item')">Add</button>31</template>传给 mutate 的每次调用专属回调仅对最后一次调用生效 —— mutateAsync 则为每次调用返回一个 Promise,因此你可在它们全部成功后等待所有结果:
1<script setup lang="ts">2import { useMutation, useQueryClient } from '@tanstack/vue-query'34const queryClient = useQueryClient()56const addMutation = useMutation({7 mutationFn: addTodo,8 onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),9})1011async function handleAddAll(todos: Array<string>) {12 try {13 await Promise.all(todos.map((todo) => addMutation.mutateAsync(todo)))14 } catch (error) {15 console.error('Failed to add todos:', error)16 }17}18</script>19 20<template>21 <button @click="handleAddAll(['Todo 1', 'Todo 2', 'Todo 3'])">Add all</button>22</template>若上述某些 修改 可独立于其他 修改 失败,且你想明确知道哪些失败了(而非在首个拒绝发生时就丢失该信息),请将 Promise.all 替换为 Promise.allSettled:
1<script setup lang="ts">2import { useMutation, useQueryClient } from '@tanstack/vue-query'34const queryClient = useQueryClient()56const addMutation = useMutation({7 mutationFn: addTodo,8 onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),9})1011async function handleAddAll(todos: Array<string>) {12 const addResults = await Promise.allSettled(13 todos.map((todo) => addMutation.mutateAsync(todo)),14 )1516 addResults.forEach((addResult, index) => {17 if (addResult.status === 'rejected') {18 console.error(`Failed to add "${todos[index]}":`, addResult.reason)19 }20 })21}22</script>23 24<template>25 <button @click="handleAddAll(['Todo 1', 'Todo 2', 'Todo 3'])">Add all</button>26</template>