前端
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 提供支持
在本页
  • Mutation 响应数据的更新
  • 避免直接修改缓存数据

这有帮助吗?

  1. Mutation

通过修改的数据更新查询内容

Mutation 响应数据的更新

当 mutation 更新服务器上的对象时*服务器通常会返回最新的对象数据。此时,我们无需重新获取查询数据(避免多余的网络请求),而是可以直接利用 mutation 返回的数据,通过 setQueryData 立即更新现有查询。

使用 setQueryData 更新本地缓存

🌰 示例:编辑 todo 项目后,直接更新查询数据:

const queryClient = useQueryClient();

const mutation = useMutation({
  mutationFn: editTodo,
  onSuccess: (data) => {
    queryClient.setQueryData(["todo", { id: 5 }], data);
  },
});

mutation.mutate({ id: 5, name: "Do the laundry" });

// 这个查询会立即获得更新后的数据,而不会重新发送请求
const { status, data, error } = useQuery({
  queryKey: ["todo", { id: 5 }],
  queryFn: fetchTodoById,
});

在 onSuccess 里,我们直接使用 mutation 返回的数据 data,调用 setQueryData 更新本地缓存,这样 useQuery 获取的数据立即同步,无需额外的网络请求。

封装成一个可复用的 useMutateTodo Hook

如果你有多个地方需要更新 todo,可以将逻辑封装成一个自定义 Hook:

const useMutateTodo = () => {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: editTodo,
    onSuccess: (data, variables) => {
      queryClient.setQueryData(["todo", { id: variables.id }], data);
    },
  });
};

然后可以这样使用:

const mutation = useMutateTodo();
mutation.mutate({ id: 5, name: "Do the laundry" });

这样,在 mutate 时,本地缓存中的 todo 也会被即时更新。

避免直接修改缓存数据

在 setQueryData 里更新数据时,必须保持数据不可变性(immutability)。

❌ 错误示例(直接修改旧数据,会导致不可预测的 bug):

queryClient.setQueryData(["posts", { id }], (oldData) => {
  if (oldData) {
    oldData.title = "my new post title"; // ❌ 直接修改 oldData
  }
  return oldData;
});

✅ 正确示例(使用对象展开运算符 ... 创建新对象):

queryClient.setQueryData(["posts", { id }], (oldData) =>
  oldData ? { ...oldData, title: "my new post title" } : oldData
);

这样可以确保 React 能正确检测到数据变更,避免出现 UI 不更新或状态不一致的问题。

上一页修改导致的失效 Invalidation From Mutations下一页乐观更新

最后更新于2个月前

这有帮助吗?