框架
版本

来自变更响应的更新

在处理在服务器上更新对象的变更时,通常会在变更的响应中自动返回新对象。与其为该项目重新获取任何查询并浪费网络调用来获取我们已经拥有的数据,不如利用变更函数返回的对象,并使用查询客户端的 setQueryData 方法立即使用新数据更新现有查询:

tsx
const queryClient = useQueryClient()

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

mutation.mutate({
  id: 5,
  name: '洗衣服',
})

// 以下查询将使用来自成功变更的响应进行更新
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: '洗衣服',
})

// 以下查询将使用来自成功变更的响应进行更新
const { status, data, error } = useQuery(() => {
  queryKey: ['todo', { id: 5 }],
  queryFn: fetchTodoById,
})

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

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

  return useMutation(() => {
    mutationFn: editTodo,
    // 注意第二个参数是 `mutate` 函数接收的变量对象
    onSuccess: (data, variables) => {
      queryClient.setQueryData(['todo', { id: variables.id }], data)
    },
  })
}
const useMutateTodo = () => {
  const queryClient = useQueryClient()

  return useMutation(() => {
    mutationFn: editTodo,
    // 注意第二个参数是 `mutate` 函数接收的变量对象
    onSuccess: (data, variables) => {
      queryClient.setQueryData(['todo', { id: variables.id }], data)
    },
  })
}

不可变性

通过 setQueryData 进行的更新必须以_不可变_的方式执行。请勿尝试通过就地修改数据(从缓存中检索的数据)来直接写入缓存。它最初可能有效,但可能会导致细微的错误。

tsx
queryClient.setQueryData(['posts', { id }], (oldData) => {
  if (oldData) {
    // ❌ 不要尝试这样做
    oldData.title = '我的新帖子标题'
  }
  return oldData
})

queryClient.setQueryData(
  ['posts', { id }],
  // ✅ 这才是正确的方法
  (oldData) =>
    oldData
      ? {
          ...oldData,
          title: '我的新帖子标题',
        }
      : oldData,
)
queryClient.setQueryData(['posts', { id }], (oldData) => {
  if (oldData) {
    // ❌ 不要尝试这样做
    oldData.title = '我的新帖子标题'
  }
  return oldData
})

queryClient.setQueryData(
  ['posts', { id }],
  // ✅ 这才是正确的方法
  (oldData) =>
    oldData
      ? {
          ...oldData,
          title: '我的新帖子标题',
        }
      : oldData,
)