乐观更新
当您在执行变更之前乐观更新(optimistically update)状态,变更可能会失败。在大多数情况下,当变更失败时,您可以触发对乐观查询(optimistic queries)的重新获取,以将其恢复为服务器的实际状态。然而,在某些情况下,重新获取可能无法正确工作,并且 mutation 的 error 可能表示某种无法重新获取的服务器问题,在这种情况下,您可以选择回滚您的更新。
要实现这一点,useMutation
的onMutate
处理程序选项允许您返回一个值,该值稍后将作为最后一个参数传递给 onError 和 onSettled 处理程序。在大多数情况下,传递回滚函数是最有用的。
Updating a list of todos when adding a new todo
const queryClient = useQueryClient();
useMutation({
mutationFn: updateTodo,
// 当调用mutate时:
onMutate: async (newTodo) => {
// 取消正在进行的重新获取
//(以免它们覆盖我们的乐观更新)
await queryClient.cancelQueries({ queryKey: ["todos"] });
// 快照先前的值
const previousTodos = queryClient.getQueryData(["todos"]);
// 乐观更新为新值
queryClient.setQueryData(["todos"], (old) => [...old, newTodo]);
//返回一个带有快照值的上下文对象
return { previousTodos };
},
// 如果变更失败,
// 使用从onMutate返回的上下文回滚
onError: (err, newTodo, context) => {
queryClient.setQueryData(["todos"], context.previousTodos);
},
//总是在错误或成功后重新获取:
onSettled: () => {
queryClient.invalidateQueries({ queryKey: ["todos"] });
},
});
更新单个 todo
useMutation({
mutationFn: updateTodo,
// 当调用mutate时:
onMutate: async (newTodo) => {
// 取消任何正在进行的重新获取
// (以免它们覆盖我们的乐观更新)
await queryClient.cancelQueries({ queryKey: ["todos", newTodo.id] });
// 快照先前的值
const previousTodo = queryClient.getQueryData(["todos", newTodo.id]);
// 乐观更新为新值
queryClient.setQueryData(["todos", newTodo.id], newTodo);
// 返回包含先前和新的待办事项的上下文
return { previousTodo, newTodo };
},
// 如果变更失败,使用我们上面返回的上下文
onError: (err, newTodo, context) => {
queryClient.setQueryData(
["todos", context.newTodo.id],
context.previousTodo
);
},
// 总是在错误或成功后重新获取:
onSettled: (newTodo) => {
queryClient.invalidateQueries({ queryKey: ["todos", newTodo.id] });
},
});
您还可以使用onSettled
函数替代单独的onError
和onSuccess
处理程序
useMutation({
mutationFn: updateTodo,
// ...
onSettled: (newTodo, error, variables, context) => {
if (error) {
// do something
}
},
});