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