来自修改响应的更新
处理那些在服务端 更新 对象的修改时,新对象通常会自动作为修改响应的一部分返回。此时,你无需重新拉取与该对象相关的任何查询(那样会浪费一次网络请求,而我们本已拥有这些数据),而是可以直接利用修改函数返回的对象,立即通过 Query Client 的 setQueryData 方法更新现有查询:
TypeScript
1const queryClient = useQueryClient()2 3const mutation = useMutation({4 mutationFn: editTodo,5 onSuccess: (data) => {6 queryClient.setQueryData(['todo', { id: 5 }], data)7 },8})9 10mutation.mutate({11 id: 5,12 name: 'Do the laundry',13})14 15// The query below will be updated with the response from the16// successful mutation17const { status, data, error } = useQuery({18 queryKey: ['todo', { id: 5 }],19 queryFn: fetchTodoById,20})你可能希望将 onSuccess 逻辑封装进一个可复用的修改中,为此你可以创建如下自定义 Hook:
TypeScript
1const useMutateTodo = () => {2 const queryClient = useQueryClient()3 4 return useMutation({5 mutationFn: editTodo,6 // Notice the second argument is the variables object that the `mutate` function receives7 onSuccess: (data, variables) => {8 queryClient.setQueryData(['todo', { id: variables.id }], data)9 },10 })11}不可变性
通过 setQueryData 进行的更新必须以 不可变 的方式进行。切勿尝试直接修改缓存中的数据(例如就地修改从缓存中获取的数据)来写入缓存。这种方式或许起初看似可行,但最终可能导致难以察觉的 bug。
TypeScript
1queryClient.setQueryData(['posts', { id }], (oldData) => {2 if (oldData) {3 // ❌ do not try this4 oldData.title = 'my new post title'5 }6 return oldData7})8 9queryClient.setQueryData(10 ['posts', { id }],11 // ✅ this is the way12 (oldData) =>13 oldData14 ? {15 ...oldData,16 title: 'my new post title',17 }18 : oldData,19)