前端
PythonJava运维数据库
TanStack Query
TanStack Query
  • getting started
    • 快速开始
    • 开发工具
    • Typescript
    • 默认配置
    • 网络模式
  • Query
    • 查询
    • 查询键
    • 查询函数
    • 查询选项
    • 并行查询
    • 有依赖的查询
    • 查询状态指示器
    • 窗口聚焦重新获取数据
    • 禁用/暂停查询
    • 查询重试
    • 分页查询
    • 无限查询
    • 初始化查询数据
  • 占位符
  • Mutation
    • 修改 Mutations
    • 主动查询失效 Query Invalidation
    • 修改导致的失效 Invalidation From Mutations
    • 通过修改的数据更新查询内容
    • 乐观更新
  • 取消查询
  • 默认查询函数
  • 过滤器
  • Suspense
  • 缓存数据
  • Api Reference
    • QueryClient
    • QueryCache
    • MutationCache
    • QueryObserver QueriesObserver
    • InfiniteQueryObserver
    • FocusManager
    • NotifyManager
    • useQuery
    • useQueries useInfiniteQuery
    • useMutation
    • useIsFetching
    • useIsMutating
    • useMutationState
    • useSuspenseQuery
    • useSuspenseInfiniteQuery
    • useSuspenseQueries
    • QueryClientProvider
    • useQueryClient
    • queryOptions
    • infiniteQueryOptions
    • QueryErrorResetBoundary
    • useQueryErrorResetBoundary
    • hydration
由 GitBook 提供支持
在本页

这有帮助吗?

  1. Mutation

修改 Mutations

与Queries不同,Mutations 主要用于创建、更新或删除数据,或者执行服务器端的副作用操作。为了支持这一点,TanStack Query 提供了 useMutation 钩子。

🌰 示例:添加一个 Todo:

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

  return (
    <div>
      {mutation.isPending ? (
        "正在添加 Todo..."
      ) : (
        <>
          {mutation.isError ? <div>发生错误: {mutation.error.message}</div> : null}

          {mutation.isSuccess ? <div>Todo 添加成功!</div> : null}

          <button
            onClick={() => {
              mutation.mutate({ id: new Date(), title: "洗衣服" });
            }}
          >
            创建 Todo
          </button>
        </>
      )}
    </div>
  );
}

mutation 在任何时候都只会处于以下状态之一:

  • isIdle 或 status === 'idle':Mutation 处于空闲状态,或者已重置。

  • isPending 或 status === 'pending':Mutation 正在执行中。

  • isError 或 status === 'error':Mutation 发生了错误。

  • isSuccess 或 status === 'success': Mutation 成功完成,数据已可用。

除此之外,还有一些额外信息可用:

  • error:当Mutation失败时,可以通过error获取错误信息。

  • data:当Mutation成功时,可以通过data获取返回的数据。

在上面的示例中,你可以看到mutate方法接受参数,并将其传递给mutationFn进行处理。

Mutation 的增强功能

在事件处理函数中调用 mutate

在 React 16 及更早版本中,mutate不能直接在事件回调函数中使用,因为 React 事件会被回收。可以通过额外包装一层来解决:

// ❌ 这样在 React 16 及更早版本会报错
const CreateTodo = () => {
  const mutation = useMutation({
    mutationFn: (event) => {
      event.preventDefault();
      return fetch("/api", new FormData(event.target));
    },
  });

  return <form onSubmit={mutation.mutate}>...</form>;
};

// ✅ 正确的写法
const CreateTodo = () => {
  const mutation = useMutation({
    mutationFn: (formData) => fetch("/api", formData);
  });

  const onSubmit = (event) => {
    event.preventDefault();
    mutation.mutate(new FormData(event.target));
  };

  return <form onSubmit={onSubmit}>...</form>;
};

重置 Mutation 状态

如果需要清除 Mutation 产生的 error 或 data,可以使用 reset 方法:

const CreateTodo = () => {
  const [title, setTitle] = useState("");
  const mutation = useMutation({ mutationFn: createTodo });

  const onCreateTodo = (e) => {
    e.preventDefault();
    mutation.mutate({ title });
  };

  return (
    <form onSubmit={onCreateTodo}>
      {mutation.error && <h5 onClick={() => mutation.reset()}>{mutation.error}</h5>}
      <input type="text" value={title} onChange={(e) => setTitle(e.target.value)} />
      <br />
      <button type="submit">创建 Todo</button>
    </form>
  );
};

Mutation 的生命周期回调

useMutation 提供了多个回调,可以在 Mutation 的不同阶段执行副作用(如更新 UI、日志记录等):

useMutation({
  mutationFn: addTodo,
  onMutate: (variables) => {
    // Mutation 即将开始!
    // 可以返回一个上下文(context),用于回滚
    return { id: 1 };
  },
  onError: (error, variables, context) => {
    console.log(`回滚操作,撤销 ID 为 ${context.id} 的更新`);
  },
  onSuccess: (data, variables, context) => {
    console.log("Mutation 成功!");
  },
  onSettled: (data, error, variables, context) => {
    console.log("无论成功还是失败,都会执行");
  },
});

这些回调可以返回 Promise,下一个回调会等待前一个回调完成后执行:

useMutation({
  mutationFn: addTodo,
  onSuccess: async () => {
    console.log("我是第一个执行的");
  },
  onSettled: async () => {
    console.log("我是第二个执行的");
  },
});

传递额外的回调

在调用 mutate 时,可以额外指定 onSuccess、onError、onSettled,这些回调会在 Mutation 完成后执行:

mutate(todo, {
  onSuccess: (data, variables, context) => {
    console.log("这是额外的 onSuccess 处理");
  },
  onError: (error, variables, context) => {
    console.log("这是额外的 onError 处理");
  },
  onSettled: (data, error, variables, context) => {
    console.log("这是额外的 onSettled 处理");
  },
});

Mutation 并发与顺序执行

默认情况下,所有 Mutation 是并行执行的。如果希望某些 Mutation 按顺序执行,可以使用 scope,拥有相同 scope.id 的 Mutation 将按照顺序执行。

const mutation = useMutation({
  mutationFn: addTodo,
  scope: {
    id: "todo",
  },
});

使用 mutateAsync 获取 Promise

如果需要在代码中以 await 方式使用 Mutation,可以使用 mutateAsync:

const mutation = useMutation({ mutationFn: addTodo });

try {
  const todo = await mutation.mutateAsync(todo);
  console.log(todo);
} catch (error) {
  console.error(error);
} finally {
  console.log("操作完成");
}

失败时自动重试

默认情况下,Mutation 失败后不会重试。但可以通过 retry 选项开启重试机制:

useMutation({
  mutationFn: addTodo,
  retry: 3, // 失败后最多重试 3 次
});

当设备离线导致 Mutation 失败时,会在设备恢复在线时自动重试。

Mutation 状态的持久化

Mutation 可以持久化存储,以便在应用重启后恢复未完成的 Mutation:

const queryClient = new QueryClient();

queryClient.setMutationDefaults(["addTodo"], {
  mutationFn: addTodo,
  retry: 3,
});

// 持久化 Mutation 状态
const state = dehydrate(queryClient);
hydrate(queryClient, state);

// 重新恢复暂停的 Mutations
queryClient.resumePausedMutations();
上一页占位符下一页主动查询失效 Query Invalidation

最后更新于2个月前

这有帮助吗?