TanStack Query 为每个查询函数提供了一个 AbortSignal 实例。当一个查询过期或不活跃时,这个 signal 会被中止。这意味着所有查询都可以被取消,并且您可以根据需要在查询函数内部响应取消操作。最棒的是,这允许您继续使用正常的 async/await 语法,同时获得自动取消的所有好处。
大多数运行时环境都支持 AbortController API,但如果您的运行时环境不支持,您需要提供一个 polyfill。市面上有几种可用的。
默认情况下,在 promises 解析之前就已卸载或未使用的查询不会被取消。这意味着在 promise 解析后,其数据仍可在缓存中访问。这在你开始获取一个查询,但组件在它完成之前被卸载时很有用。如果你重新挂载该组件,并且查询尚未被垃圾回收,数据将可用。
但是,如果您使用了 AbortSignal,Promise 将被取消(例如,中止 fetch),因此,Query 也必须被取消。取消查询将导致其状态恢复到之前的状态。
const query = useQuery({
queryKey: ['todos'],
queryFn: async ({ signal }) => {
const todosResponse = await fetch('/todos', {
// Pass the signal to one fetch
signal,
})
const todos = await todosResponse.json()
const todoDetails = todos.map(async ({ details }) => {
const response = await fetch(details, {
// Or pass it to several
signal,
})
return response.json()
})
return Promise.all(todoDetails)
},
})
const query = useQuery({
queryKey: ['todos'],
queryFn: async ({ signal }) => {
const todosResponse = await fetch('/todos', {
// Pass the signal to one fetch
signal,
})
const todos = await todosResponse.json()
const todoDetails = todos.map(async ({ details }) => {
const response = await fetch(details, {
// Or pass it to several
signal,
})
return response.json()
})
return Promise.all(todoDetails)
},
})
import axios from 'axios'
const query = useQuery({
queryKey: ['todos'],
queryFn: ({ signal }) =>
axios.get('/todos', {
// Pass the signal to `axios`
signal,
}),
})
import axios from 'axios'
const query = useQuery({
queryKey: ['todos'],
queryFn: ({ signal }) =>
axios.get('/todos', {
// Pass the signal to `axios`
signal,
}),
})
import axios from 'axios'
const query = useQuery({
queryKey: ['todos'],
queryFn: ({ signal }) => {
// Create a new CancelToken source for this request
const CancelToken = axios.CancelToken
const source = CancelToken.source()
const promise = axios.get('/todos', {
// Pass the source token to your request
cancelToken: source.token,
})
// Cancel the request if TanStack Query signals to abort
signal?.addEventListener('abort', () => {
source.cancel('Query was cancelled by TanStack Query')
})
return promise
},
})
import axios from 'axios'
const query = useQuery({
queryKey: ['todos'],
queryFn: ({ signal }) => {
// Create a new CancelToken source for this request
const CancelToken = axios.CancelToken
const source = CancelToken.source()
const promise = axios.get('/todos', {
// Pass the source token to your request
cancelToken: source.token,
})
// Cancel the request if TanStack Query signals to abort
signal?.addEventListener('abort', () => {
source.cancel('Query was cancelled by TanStack Query')
})
return promise
},
})
const 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()
})
},
})
const 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()
})
},
})
一个 AbortSignal 可以在客户端 request 方法中设置。
const client = new GraphQLClient(endpoint)
const query = useQuery({
queryKey: ['todos'],
queryFn: ({ signal }) => {
client.request({ document: query, signal })
},
})
const client = new GraphQLClient(endpoint)
const query = useQuery({
queryKey: ['todos'],
queryFn: ({ signal }) => {
client.request({ document: query, signal })
},
})
一个 AbortSignal 可以在 GraphQLClient 构造函数中设置。
const query = useQuery({
queryKey: ['todos'],
queryFn: ({ signal }) => {
const client = new GraphQLClient(endpoint, {
signal,
})
return client.request(query, variables)
},
})
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()
function onButtonClick() {
queryClient.cancelQueries({ queryKey: ['todos'] })
}
const query = useQuery({
queryKey: ['todos'],
queryFn: async ({ signal }) => {
const resp = await fetch('/todos', { signal })
return resp.json()
},
})
const queryClient = useQueryClient()
function onButtonClick() {
queryClient.cancelQueries({ queryKey: ['todos'] })
}
取消选项用于控制查询取消操作的行为。
// Cancel specific queries silently
await queryClient.cancelQueries({ queryKey: ['posts'] }, { silent: true })
// Cancel specific queries silently
await queryClient.cancelQueries({ queryKey: ['posts'] }, { silent: true })
取消选项对象支持以下属性
在使用 Suspense hooks 时,取消功能不起作用:useSuspenseQuery, useSuspenseQueries 和 useSuspenseInfiniteQuery。