框架
版本

来自变更响应的更新

在处理更新服务器上的对象的mutation时,通常mutation的响应会直接返回新的对象。与其重新获取该项目的任何查询并浪费一个用于我们已拥有数据的网络调用,我们可以利用mutation函数返回的对象,使用Query Client 的 setQueryData 方法立即使用新数据更新现有查询。

tsx
const queryClient = useQueryClient()

const mutation = useMutation(() => {
  mutationFn: editTodo,
  onSuccess: (data) => {
    queryClient.setQueryData(['todo', { id: 5 }], data)
  },
})

mutation.mutate({
  id: 5,
  name: 'Do the laundry',
})

// The query below will be updated with the response from the
// successful mutation
const { status, data, error } = useQuery(() => {
  queryKey: ['todo', { id: 5 }],
  queryFn: fetchTodoById,
})
const queryClient = useQueryClient()

const mutation = useMutation(() => {
  mutationFn: editTodo,
  onSuccess: (data) => {
    queryClient.setQueryData(['todo', { id: 5 }], data)
  },
})

mutation.mutate({
  id: 5,
  name: 'Do the laundry',
})

// The query below will be updated with the response from the
// successful mutation
const { status, data, error } = useQuery(() => {
  queryKey: ['todo', { id: 5 }],
  queryFn: fetchTodoById,
})

你可能希望将 onSuccess 逻辑绑定到一个可重用的变更中,为此你可以像这样创建一个自定义钩子

tsx
const useMutateTodo = () => {
  const queryClient = useQueryClient()

  return useMutation(() => {
    mutationFn: editTodo,
    // Notice the second argument is the variables object that the `mutate` function receives
    onSuccess: (data, variables) => {
      queryClient.setQueryData(['todo', { id: variables.id }], data)
    },
  })
}
const useMutateTodo = () => {
  const queryClient = useQueryClient()

  return useMutation(() => {
    mutationFn: editTodo,
    // Notice the second argument is the variables object that the `mutate` function receives
    onSuccess: (data, variables) => {
      queryClient.setQueryData(['todo', { id: variables.id }], data)
    },
  })
}

不变性

setQueryData 的更新必须以不可变的方式执行。**切勿**尝试通过就地修改数据(从缓存中检索到的数据)来直接写入缓存。这可能起初有效,但可能会导致后续出现不易察觉的 bug。

tsx
queryClient.setQueryData(['posts', { id }], (oldData) => {
  if (oldData) {
    // ❌ do not try this
    oldData.title = 'my new post title'
  }
  return oldData
})

queryClient.setQueryData(
  ['posts', { id }],
  // ✅ this is the way
  (oldData) =>
    oldData
      ? {
          ...oldData,
          title: 'my new post title',
        }
      : oldData,
)
queryClient.setQueryData(['posts', { id }], (oldData) => {
  if (oldData) {
    // ❌ do not try this
    oldData.title = 'my new post title'
  }
  return oldData
})

queryClient.setQueryData(
  ['posts', { id }],
  // ✅ this is the way
  (oldData) =>
    oldData
      ? {
          ...oldData,
          title: 'my new post title',
        }
      : oldData,
)