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

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 不更新或状态不一致的问题。

最后更新于

这有帮助吗?