乐观更新与反应-查询(TRPC)



我不确定如何与trpc进行乐观更新?这是"内置的"吗?还是我必须使用react-query的useQuery钩子?

到目前为止,我正在尝试这样做,但它不工作:

const queryClient = useQueryClient();
const updateWord = trpc.word.update.useMutation({
onMutate: async newTodo => {
// Cancel any outgoing refetches (so they don't overwrite our optimistic update)
await queryClient.cancelQueries({ queryKey: ['text', 'getOne'] })
// Snapshot the previous value
const previousText = queryClient.getQueryData(['text', 'getOne'])
// Optimistically update to the new value
queryClient.setQueryData(['text', 'getOne'], old => old ? {...old, { title: "Hello" }} : undefined)
// Return a context object with the snapshotted value
return { previousText }
},
//...

这看起来应该有意义吗?它正在更新值,但不乐观。

trpc v10通过自己的useContext钩子提供了大多数queryClient函数的类型安全变体:

const utils = trpc.useContext()

那么,你应该能够做到:

utils.text.getOne.cancel()
utils.text.getOne.getData()
utils.text.getOne.setData()

见:https://trpc.io/docs/useContext

经过2天的摸索,我终于找到了解决这个问题的方法。

我们必须像前面提到的那样使用api.useContext()。

下面是正在工作的完整的乐观更新示例。

import { useCallback, useState } from "react";
import { Button } from "../shadcn-ui/button";
import { Input } from "../shadcn-ui/input";
import { api } from "~/utils/api";
import { useToast } from "~/components/shadcn-ui/use-toast";
import { type TodoWithUser } from "./Todo.type";
import { useSession } from "next-auth/react";
export const TodoBar = () => {
const [todo, setTodo] = useState("");
const { data: session } = useSession();
const utils = api.useContext();
const addTodo = api.todo.create.useMutation({
onMutate: async (newTodo) => {
setTodo("");
// Cancel any outgoing refetches
// (so they don't overwrite our optimistic update)
await utils.todo.findAll.cancel();
// Snapshot the previous value
const previousTodos = utils.todo.findAll.getData();
// Optimistically update to the new value
utils.todo.findAll.setData(
undefined,
(oldQueryData: TodoWithUser[] | undefined) =>
[
...(oldQueryData ?? []),
{
author: {
name: session?.user?.name,
id: session?.user?.id,
},
content: newTodo.content,
done: false,
createdAt: new Date(),
updatedAt: new Date(),
},
] as TodoWithUser[]
);
// Return a context object with the snapshotted value
return { previousTodos };
},
onError: (err, _newTodo, context) => {
// Rollback to the previous value if mutation fails
utils.todo.findAll.setData(undefined, context?.previousTodos);
},
onSuccess: () => {
console.log("inside onSuccess");
},
onSettled: () => {
void utils.todo.findAll.invalidate();
},
});
const handleInputOnChange = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => {
setTodo(event.target.value);
},
[]
);
const handleAddTodo = useCallback(() => {
addTodo.mutate({
content: todo,
});
}, [addTodo, todo]);
return (
<div className="flex w-full items-center space-x-2 self-center px-6 pt-2  md:w-2/3 md:flex-grow-0 lg:w-2/3 xl:w-1/2">
<Input
placeholder="Enter your task!"
value={todo}
onChange={handleInputOnChange}
/>
<Button type="submit" onClick={handleAddTodo}>
Add
</Button>
</div>
);
};

最新更新