取消查询
TanStack Query 会为每个查询函数提供一个 AbortSignal 实例。当一个查询变得过时或非激活时,这个 signal 将会被中止。这意味着所有查询都是可取消的,如果需要,你可以在查询函数内部响应此取消操作。最棒的是,这允许你继续使用正常的 async/await 语法,同时获得自动取消的所有好处。
AbortController API 在大多数运行时环境中都可用,但如果你的运行时环境不支持它,你需要提供一个 polyfill。有多个可用的 polyfill。
默认行为
默认情况下,那些在 Promise 解析之前就已卸载或变为未使用的查询不会被取消。这意味着在 Promise 解析后,结果数据将仍会存在于缓存中。这对于你已经开始接收一个查询,但在其完成前卸载了组件的情况很有帮助。如果你再次挂载该组件,并且该查询尚未被垃圾回收,数据将仍然可用。
然而,如果你使用了 AbortSignal,Promise 将被取消(例如,中止 fetch 请求),因此查询也必须被取消。取消查询将导致其状态被回滚到之前的状态。
使用 fetch
fetchconst query = useQuery({
queryKey: ['todos'],
queryFn: async ({ signal }) => {
const todosResponse = await fetch('/todos', {
// 将 signal 传递给一次 fetch
signal,
})
const todos = await todosResponse.json()
const todoDetails = todos.map(async ({ details }) => {
const response = await fetch(details, {
// 或传递给多次 fetch
signal,
})
return response.json()
})
return Promise.all(todoDetails)
},
})使用 axios v0.22.0+
axios v0.22.0+import axios from 'axios'
const query = useQuery({
queryKey: ['todos'],
queryFn: ({ signal }) =>
axios.get('/todos', {
// 将 signal 传递给 `axios`
signal,
}),
})使用低于 v0.22.0 版本的 axios
axiosimport axios from 'axios'
const query = useQuery({
queryKey: ['todos'],
queryFn: ({ signal }) => {
// 为此请求创建一个新的 CancelToken 源
const CancelToken = axios.CancelToken
const source = CancelToken.source()
const promise = axios.get('/todos', {
// 将源令牌传递给你的请求
cancelToken: source.token,
})
// 如果 TanStack Query 发出中止信号,则取消请求
signal?.addEventListener('abort', () => {
source.cancel('Query was cancelled by TanStack Query')
})
return promise
},
})使用 XMLHttpRequest
XMLHttpRequestconst query = useQuery({
queryKey: ['todos'],
queryFn: ({ signal }) => {
return new Promise((resolve, reject) => {
var oReq = new XMLHttpRequest()
oReq.addEventListener('load', () => {
resolve(JSON.parse(oReq.responseText))
})
signal?.addEventListener('abort', () => {
oReq.abort()
reject()
})
oReq.open('GET', '/todos')
oReq.send()
})
},
})使用 graphql-request
graphql-request可以在客户端的 request 方法中设置 AbortSignal。
const client = new GraphQLClient(endpoint)
const query = useQuery({
queryKey: ['todos'],
queryFn: ({ signal }) => {
client.request({ document: query, signal })
},
})使用低于 v4.0.0 版本的 graphql-request
graphql-request可以在 GraphQLClient 构造函数中设置 AbortSignal。
const query = useQuery({
queryKey: ['todos'],
queryFn: ({ signal }) => {
const client = new GraphQLClient(endpoint, {
signal,
})
return client.request(query, variables)
},
})手动取消
你可能希望手动取消一个查询。例如,如果请求耗时较长,你可以允许用户点击一个取消按钮来停止请求。为此,你只需调用 queryClient.cancelQueries({ queryKey }),这将取消查询并将其状态回滚到之前的状态。如果你在查询函数中使用了传入的 signal,TanStack Query 还会额外取消 Promise。
const query = useQuery({
queryKey: ['todos'],
queryFn: async ({ signal }) => {
const resp = await fetch('/todos', { signal })
return resp.json()
},
})
const queryClient = useQueryClient()
return (
<button
onClick={(e) => {
e.preventDefault()
queryClient.cancelQueries({ queryKey: ['todos'] })
}}
>
取消
</button>
)取消选项(Cancel Options)
取消选项(Cancel Options)取消选项用于控制查询取消操作的行为。
// 静默取消特定查询
await queryClient.cancelQueries({ queryKey: ['posts'] }, { silent: true })取消选项对象支持以下属性:
silent?: boolean当设置为
true时,会抑制CancelledError向观察者(例如onError回调)和相关通知的传播,并返回重试 Promise 而不是拒绝。默认值为
false
revert?: boolean当设置为
true时,将查询的状态(数据和状态)恢复到飞行中获取之前的状态,将fetchStatus设置回idle,并且仅在没有先前数据时才抛出错误。默认值为
true
局限性
当使用 Suspense 相关的 Hook 时,取消功能不起作用:useSuspenseQuery、useSuspenseQueries 和 useSuspenseInfiniteQuery。
最后更新于
这有帮助吗?