---
id: query.mutation-cache-update
kind: recipe
product: query
framework: react
locale: zh-CN
revision: 2
sourceCheckedOn: "2026-08-03"
versionRange: "^5"
verifiedAgainst: "@tanstack/react-query@5.101.4"
contentModel: 2
packages:
  - "@tanstack/react-query"
tasks:
  - "create-mutation"
  - "update-query-cache"
  - "invalidate-query"
sourceRefs:
  - "https://tanstack.com/query/latest/docs/framework/react/guides/mutations"
  - "https://tanstack.com/query/latest/docs/framework/react/guides/updates-from-mutation-responses"
  - "https://tanstack.com/query/latest/docs/framework/react/guides/invalidations-from-mutations"
---

# 用 Mutation 响应更新缓存

> 当写入响应包含完整实体时用 setQueryData；无法推导正确缓存时改用 invalidateQueries。

## 执行契约

- **适用场景:** Mutation 响应包含可信的最新实体，可直接更新精确缓存并减少额外请求。
- **不要使用:** 响应不完整或会影响未知列表集合时，优先做有界失效而不是猜测所有缓存形态。
- **前置检查:** 列出受影响 Query Key、服务端响应类型以及失败时应保留的旧值。
- **验证结果:** 成功后详情与列表一致，失败后旧缓存不变；检查没有无关 Query 被失效。
- **失败模式:** 若列表与详情分叉，响应只写入了一处或 Key 不一致；集中 Key 工厂并明确更新范围。
- **安全边界:** 客户端缓存更新不代表写入成功或已授权；仅使用服务端确认后的响应。

## 直接写回

mutationFn 返回服务端创建后的对象。onSuccess 通过函数式 setQueryData 不可变地创建新数组。不要原地修改 current。

File: `src/features/issues/useCreateIssue.ts`

```tsx
export function useCreateIssue() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: createIssue,
    onSuccess: (created) => {
      queryClient.setQueryData<Issue[]>(['issues'], (current = []) => [
        created,
        ...current,
      ])
    },
  })
}
```

## 何时失效

如果服务端会重排列表、计算聚合、执行权限过滤，或响应没有包含所有相关字段，就在成功后 await invalidateQueries({ queryKey: ['issues'] })。不要同时盲目 set 与 invalidate。

## 错误与并发

用 isPending 禁止重复提交或显示进度，用 isError 提供可恢复反馈。只有在实现取消、快照和回滚后才做乐观更新。

## Official sources

- https://tanstack.com/query/latest/docs/framework/react/guides/mutations
- https://tanstack.com/query/latest/docs/framework/react/guides/updates-from-mutation-responses
- https://tanstack.com/query/latest/docs/framework/react/guides/invalidations-from-mutations
