---
id: query-cancellation
track: learn
product: query
locale: zh-CN
order: 13
revision: 2
sourceCheckedOn: "2026-08-03"
versionRange: "Query ^5"
verifiedAgainst: "@tanstack/react-query@5.101.4"
contentModel: 2
prerequisites:
  - "已理解 queryKey、queryFn 与缓存状态"
sourceRefs:
  - "https://tanstack.com/query/latest/docs/framework/react/guides/query-cancellation"
  - "https://tanstack.com/query/latest/docs/framework/react/guides/query-functions"
---

# 让 Query 取消真正传到网络层

> 消费 queryFn 提供的 AbortSignal，让失效的 fetch 停止并理解取消后的缓存状态。

**Outcome:** 能把同一个 signal 传给一组相关请求，区分组件卸载与真正取消，并知道 Suspense 查询的限制。

## 提供 signal 不等于自动中止网络

Query 会向 queryFn 提供 AbortSignal，但默认未使用的请求仍可完成并写入缓存。只有请求库消费 signal 后，取消才会中止 Promise，并让 Query 恢复到取消前的状态。

## 把同一个 signal 传完整条请求链

原生 fetch 直接接受 signal。先检查 response.ok，再解析 JSON；一个 queryFn 发出多个相关请求时，将相同 signal 传给每一个请求，避免只取消链路的一部分。

> **Note:** 官方当前说明：useSuspenseQuery、useSuspenseQueries 和 useSuspenseInfiniteQuery 不支持这一取消行为。

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

```ts
import { queryOptions } from '@tanstack/react-query'

export const issuesOptions = queryOptions({
  queryKey: ['issues', 'list'] as const,
  queryFn: async ({ signal }) => {
    const response = await fetch('/api/issues', { signal })
    if (!response.ok) throw new Error('Unable to load issues')
    return response.json()
  },
})
```

## 实践与验证

### 完成检查点

Query 提供的同一 AbortSignal 传入整条请求链，过期请求停止 I/O 且不伪装成成功。

### 动手练习

实现快速切换 Issue 时取消旧详情请求，并记录 AbortError 与普通网络错误的不同处理。

### 验证方法

在慢速网络下快速切换路由；旧请求应显示为 canceled，新请求正常完成，缓存不出现空数据闪烁。

### 常见错误

- 拿到 signal 却没有传给 fetch。
- 捕获取消异常后返回空数组，导致 Query 标记成功。

## Official sources

- https://tanstack.com/query/latest/docs/framework/react/guides/query-cancellation
- https://tanstack.com/query/latest/docs/framework/react/guides/query-functions
