执行契约
- 适用场景
- Mutation 响应包含可信的最新实体,可直接更新精确缓存并减少额外请求。
- 不要使用
- 响应不完整或会影响未知列表集合时,优先做有界失效而不是猜测所有缓存形态。
- 前置检查
- 列出受影响 Query Key、服务端响应类型以及失败时应保留的旧值。
- 验证结果
- 成功后详情与列表一致,失败后旧缓存不变;检查没有无关 Query 被失效。
- 失败模式
- 若列表与详情分叉,响应只写入了一处或 Key 不一致;集中 Key 工厂并明确更新范围。
- 安全边界
- 客户端缓存更新不代表写入成功或已授权;仅使用服务端确认后的响应。
直接写回
mutationFn 返回服务端创建后的对象。onSuccess 通过函数式 setQueryData 不可变地创建新数组。不要原地修改 current。
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 提供可恢复反馈。只有在实现取消、快照和回滚后才做乐观更新。