修改 Mutations

与查询(queries)不同,变更通常用于创建/更新/删除数据或执行服务器端副作用。为此,TanStack Query 导出了一个 useMutation Hook。

以下是一个将新待办事项添加到服务器的变更示例:

function App() {
  const mutation = useMutation({
    mutationFn: (newTodo) => {
      return axios.post('/todos', newTodo)
    },
  })

  return (
    <div>
      {mutation.isPending ? (
        '正在添加待办事项...'
      ) : (
        <>
          {mutation.isError ? (
            <div>发生错误:{mutation.error.message}</div>
          ) : null}

          {mutation.isSuccess ? <div>待办事项已添加!</div> : null}

          <button
            onClick={() => {
              mutation.mutate({ id: new Date(), title: '洗衣服' })
            }}
          >
            创建待办事项
          </button>
        </>
      )}
    </div>
  )
}

在任何给定时刻,一个变更只能处于以下状态之一:

  • isIdlestatus === 'idle' - 变更当前处于空闲或初始/重置状态

  • isPendingstatus === 'pending' - 变更正在运行

  • isErrorstatus === 'error' - 变更遇到了错误

  • isSuccessstatus === 'success' - 变更成功,且变更数据可用

除了这些主要状态外,根据变更的状态,还可以获得更多信息:

  • error - 如果变更处于 error 状态,可以通过 error 属性获取错误信息。

  • data - 如果变更处于 success 状态,可以通过 data 属性获取数据。

在上面的示例中,你还看到可以通过向 mutate 函数传递单个变量或对象来为你的变更函数提供变量。

即使只有变量,变更也并非特别之处,但当与 onSuccess 选项、Query Client 的 invalidateQueries 方法 和 Query Client 的 setQueryData 方法 一起使用时,变更就成为了一个非常强大的工具。

重要mutate 函数是一个异步函数,这意味着你不能在 React 16 及更早版本的事件回调中直接使用它。如果你需要在 onSubmit 中访问事件,你需要将 mutate 包装在另一个函数中。这是由于 React 事件池化arrow-up-right 造成的。

重置变更状态

有时你可能需要清除变更请求的 errordata。为此,你可以使用 reset 函数来处理:

变更副作用

useMutation 提供了一些辅助选项,允许在变更生命周期的任何阶段快速轻松地执行副作用。这些选项对于在变更后使查询失效并重新获取以及乐观更新都非常有用。

如果在任何回调函数中返回一个 Promise,它将首先被等待,然后才会调用下一个回调:

你可能会发现,在调用 mutate 时,你想触发除了 useMutation 中定义的之外的额外回调。这可以用来触发组件特定的副作用。为此,你可以在 mutate 函数的变量之后提供任何相同的回调选项。支持的选项包括:onSuccessonErroronSettled。请注意,如果在变更完成前组件已经卸载,这些额外的回调将不会运行。

连续变更

在处理连续变更时,处理 onSuccessonErroronSettled 回调的方式略有不同。当这些回调作为参数传递给 mutate 函数时,它们将只执行一次,并且只有在组件仍然挂载时才会执行。这是因为每次调用 mutate 函数时,变更观察器都会被移除并重新订阅。相反,useMutation 的处理程序会为每次 mutate 调用执行。

请注意,传递给 useMutationmutationFn 很可能是异步的。在这种情况下,变更完成的顺序可能与 mutate 函数调用的顺序不同。

Promise

使用 mutateAsync 代替 mutate 来获取一个 Promise,该 Promise 在成功时解析,在错误时抛出。例如,这可以用来组合副作用。

重试

默认情况下,TanStack Query 在出错时不会重试变更,但可以通过 retry 选项实现:

如果变更因设备离线而失败,当设备重新连接时,它们将按相同顺序重试。

持久化变更

如果需要,变更可以持久化到存储中,并在稍后恢复。这可以通过 hydration 函数来实现:

持久化离线变更

如果你使用 persistQueryClient 插件 持久化离线变更,除非你提供一个默认的变更函数,否则在页面重新加载后无法恢复变更。

这是一个技术限制。当持久化到外部存储时,只有变更的状态被持久化,因为函数无法被序列化。补水后,触发变更的组件可能未挂载,因此调用 resumePausedMutations 可能会产生错误:No mutationFn found

我们还有一个全面的 离线示例,涵盖了查询和变更。

变更作用域

默认情况下,所有变更都是并行运行的——即使你多次调用同一个变更的 .mutate()。可以为变更指定一个带有 idscope 来避免这种情况。所有具有相同 scope.id 的变更将串行运行,这意味着当它们被触发时,如果该作用域中已有变更正在进行,它们将从 isPaused: true 状态开始。它们将被放入队列,并在轮到它们时自动恢复。

进一步阅读

有关变更的更多信息,请查看社区资源中的 #12: 掌握 React Query 中的变更。

最后更新于