来自修改响应的更新
在处理那些会在服务端 更新 对象的修改(mutation)时,新对象通常会自动包含在修改响应中返回。与其重新拉取(refetch)相关查询、浪费一次本可避免的网络请求(因为我们已经拥有该数据),不如直接利用修改函数返回的对象,通过 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 todoQuery = useQuery(() => ({18 queryKey: ['todo', { id: 5 }],19 queryFn: fetchTodoById,20}))你可能希望将 onSuccess 逻辑封装进一个可复用的修改中,为此你可以创建如下自定义原语:
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)