useMutation
1function useMutation<TData = unknown, TError = Error, TVariables = void, TOnMutateResult = unknown>(options: UseMutationOptions<TData, TError, TVariables, TOnMutateResult>, queryClient?: Accessor<QueryClient>): UseMutationResult<TData, TError, TVariables, TOnMutateResult>;定义于:packages/solid-query/src/useMutation.ts:170
与查询不同,修改通常用于创建/更新/删除数据或执行服务端副作用(server side-effects)。useMutation 是用于此目的的原始 API。
类型参数
TData
TData = unknown
TError
TError = Error
TVariables
TVariables = void
TOnMutateResult
TOnMutateResult = unknown
参数
options
UseMutationOptions<TData, TError, TVariables, TOnMutateResult>
一个返回 UseMutationOptions 的 accessor。
options 属性
基于 MutationOptions 构建。参见上方类型定义以了解其具体变更内容。
queryClient?
Accessor<QueryClient>
一个自定义 QueryClient 的 accessor。若未提供,则使用离当前组件最近的上下文中的 QueryClient。
返回值
UseMutationResult<TData, TError, TVariables, TOnMutateResult>
mutate/mutateAsync 还支持将 onSuccess/onError/onSettled 回调函数作为第二个参数传入,这在触发调用点副作用(例如导航)时非常有用,且无需将这些副作用耦合到共享的修改定义中。Hook 级回调(传入 options 的那些)会在每次修改时触发;而每次调用的回调仅对最近一次调用生效,且仅在组件仍处于挂载状态时触发 —— 若组件在修改完成前卸载,则会移除订阅,从而阻止这些回调执行。
返回结果属性
基于 MutationObserverBaseResult 构建。参见上方类型定义以了解其具体变更内容。
示例
1import { useMutation, useQueryClient } from '@tanstack/solid-query'2 3function TodoItem(props: { id: number }) {4 const queryClient = useQueryClient()5 6 const deleteTodoMutation = useMutation(() => ({7 mutationFn: deleteTodo,8 onSuccess: () => {9 queryClient.invalidateQueries({ queryKey: ['todos'] })10 },11 }))12 13 return (14 <button onClick={() => deleteTodoMutation.mutate({ id: props.id })} disabled={deleteTodoMutation.isPending}>15 Delete16 </button>17 )18}渲染修改自身的状态,而不仅仅是发起修改:
1import { Match, Switch } from 'solid-js'2import { useMutation, useQueryClient } from '@tanstack/solid-query'3 4function AddTodo() {5 const queryClient = useQueryClient()6 7 const addMutation = useMutation(() => ({8 mutationFn: addTodo,9 onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),10 }))11 12 return (13 <Switch fallback={<button onClick={() => addMutation.mutate('Item')}>Add</button>}>14 <Match when={addMutation.isPending}>Adding todo...</Match>15 <Match when={addMutation.isError}>16 <div>An error occurred: {addMutation.error?.message}</div>17 <button onClick={() => addMutation.mutate('Item')}>Add</button>18 </Match>19 </Switch>20 )21}通过 onMutate 实现乐观更新,并在 onError 时回滚:
1import { useMutation, useQueryClient } from '@tanstack/solid-query'2 3function AddTodo() {4 const queryClient = useQueryClient()5 6 const addMutation = useMutation(() => ({7 mutationFn: addTodo,8 onMutate: async (newTodo) => {9 await queryClient.cancelQueries({ queryKey: ['todos'] })10 const previousTodos = queryClient.getQueryData<Array<string>>(['todos'])11 12 queryClient.setQueryData<Array<string>>(['todos'], (old) => [13 ...(old ?? []),14 newTodo,15 ])16 17 // 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 28 return (29 <button onClick={() => addMutation.mutate('Item')}>Add</button>30 )31}传给 mutate 的每次调用回调仅对最后一次调用生效 —— mutateAsync 则为每次调用返回一个 Promise,因此你可以在它们全部成功后等待所有 Promise 完成:
1import { useMutation, useQueryClient } from '@tanstack/solid-query'2 3function AddTodos() {4 const queryClient = useQueryClient()5 6 const addMutation = useMutation(() => ({7 mutationFn: addTodo,8 onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),9 }))10 11 async 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 19 return (20 <button onClick={() => handleAddAll(['Todo 1', 'Todo 2', 'Todo 3'])}>21 Add all22 </button>23 )24}如果上述某些修改可能独立于其他修改而失败,且你想明确知道哪些修改失败了(而非在第一个修改拒绝时就丢失该信息),请将 Promise.all 替换为 Promise.allSettled:
1import { useMutation, useQueryClient } from '@tanstack/solid-query'2 3function AddTodos() {4 const queryClient = useQueryClient()5 6 const addMutation = useMutation(() => ({7 mutationFn: addTodo,8 onSuccess: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),9 }))10 11 async function handleAddAll(todos: Array<string>) {12 const addResults = await Promise.allSettled(13 todos.map((todo) => addMutation.mutateAsync(todo)),14 )15 16 addResults.forEach((addResult, index) => {17 if (addResult.status === 'rejected') {18 console.error(`Failed to add "${todos[index]}":`, addResult.reason)19 }20 })21 }22 23 return (24 <button onClick={() => handleAddAll(['Todo 1', 'Todo 2', 'Todo 3'])}>25 Add all26 </button>27 )28}