createMutation
1const createMutation: <TData, TError, TVariables, TOnMutateResult>(options: UseMutationOptions<TData, TError, TVariables, TOnMutateResult>, queryClient?: Accessor<QueryClient>) => UseMutationResult<TData, TError, TVariables, TOnMutateResult> = useMutation;定义于:packages/solid-query/src/index.ts:80
与查询不同,修改通常用于创建/更新/删除数据或执行服务端副作用。useMutation 是用于该目的的底层原语。
类型参数
TData
TData = unknown
TError
TError = Error
TVariables
TVariables = void
TOnMutateResult
TOnMutateResult = unknown
参数
options
UseMutationOptions<TData, TError, TVariables, TOnMutateResult>
一个返回待使用的 UseMutationOptions 的访问器。
queryClient?
Accessor<QueryClient>
一个自定义 QueryClient 的访问器。否则将使用最近上下文中的那个。
返回值
UseMutationResult<TData, TError, TVariables, TOnMutateResult>
mutate/mutateAsync 还接受以第二个参数形式传入的每次调用专属的 onSuccess/onError/onSettled 回调函数,这在触发调用点副作用(例如导航)时很有用,且无需将这些副作用耦合到共享的修改定义中。Hook 级回调(传给 options)会在每次修改时触发;而每次调用专属的回调仅对最近一次调用生效,且仅在组件仍处于挂载状态时触发——若在修改完成前卸载组件,则会移除订阅,从而阻止这些回调被触发。
示例
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,因此你可在所有调用成功后等待全部完成:
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}