查询取消
TanStack Query 会为每个查询函数提供一个 AbortSignal 实例。当查询变为过期或非活跃状态时,该 signal 将被中止。这意味着所有查询均可取消,且你可根据需要在查询函数内响应取消操作。最棒之处在于,你可继续使用常规的 async/await 语法,同时获得自动取消的所有优势。
AbortController API 在 大多数运行时环境 中均可用;但若你的运行时环境不支持它,则需提供 polyfill。目前有 多个可用选项。
默认行为
默认情况下,组件卸载或查询变为未使用状态(此时其 Promise 尚未解析)时,查询 不会 被取消。这意味着 Promise 解析后,所得数据将存入缓存。若你已发起某查询,但组件在查询完成前即被卸载,此行为便十分有用:当你再次挂载该组件且该查询尚未被垃圾回收时,数据即可立即可用。
然而,若你实际使用了 AbortSignal,则 Promise 将被取消(例如中止 fetch 请求),因此该查询也必须被取消。取消查询将导致其状态 回滚 至此前状态。
使用 fetch
TypeScript
1const todosQuery = useQuery(() => () => ({2 queryKey: ['todos'],3 queryFn: async ({ signal }) => {4 const todosResponse = await fetch('/todos', {5 // Pass the signal to one fetch6 signal,7 })8 const todos = await todosResponse.json()9 10 const todoDetails = todos.map(async ({ details }) => {11 const response = await fetch(details, {12 // Or pass it to several13 signal,14 })15 return response.json()16 })17 18 return Promise.all(todoDetails)19 },20}))使用 axios v0.22.0+
TypeScript
1import axios from 'axios'2 3const todosQuery = useQuery(() => () => ({4 queryKey: ['todos'],5 queryFn: ({ signal }) =>6 axios.get('/todos', {7 // Pass the signal to `axios`8 signal,9 }),10}))使用低于 v0.22.0 版本的 axios
TypeScript
1import axios from 'axios'2 3const todosQuery = useQuery(() => () => ({4 queryKey: ['todos'],5 queryFn: ({ signal }) => {6 // Create a new CancelToken source for this request7 const CancelToken = axios.CancelToken8 const source = CancelToken.source()9 10 const promise = axios.get('/todos', {11 // Pass the source token to your request12 cancelToken: source.token,13 })14 15 // Cancel the request if TanStack Query signals to abort16 signal?.addEventListener('abort', () => {17 source.cancel('Query was cancelled by TanStack Query')18 })19 20 return promise21 },22}))使用 XMLHttpRequest
TypeScript
1const todosQuery = useQuery(() => () => ({2 queryKey: ['todos'],3 queryFn: ({ signal }) => {4 return new Promise((resolve, reject) => {5 var oReq = new XMLHttpRequest()6 oReq.addEventListener('load', () => {7 resolve(JSON.parse(oReq.responseText))8 })9 signal?.addEventListener('abort', () => {10 oReq.abort()11 reject()12 })13 oReq.open('GET', '/todos')14 oReq.send()15 })16 },17}))使用 graphql-request
可在客户端 request 方法中设置 AbortSignal。
TypeScript
1const client = new GraphQLClient(endpoint)2 3const todosQuery = useQuery(() => () => ({4 queryKey: ['todos'],5 queryFn: ({ signal }) => {6 client.request({ document: query, signal })7 },8}))使用低于 v4.0.0 版本的 graphql-request
可在 GraphQLClient 构造函数中设置 AbortSignal。
TypeScript
1const todosQuery = useQuery(() => () => ({2 queryKey: ['todos'],3 queryFn: ({ signal }) => {4 const client = new GraphQLClient(endpoint, {5 signal,6 })7 return client.request(query, variables)8 },9}))手动取消
你可能需要手动取消某个查询。例如,若请求耗时较长,你可允许用户点击取消按钮以终止请求。为此,只需调用 queryClient.cancelQueries({ queryKey }),该方法将取消查询并将其状态回滚至此前状态。若你已在查询函数中使用了传入的 signal,TanStack Query 还将额外取消该 Promise。
TypeScript
1const todosQuery = useQuery(() => () => ({2 queryKey: ['todos'],3 queryFn: async ({ signal }) => {4 const resp = await fetch('/todos', { signal })5 return resp.json()6 },7}))8 9const queryClient = useQueryClient()10 11return (12 <button13 onClick={(e) => {14 e.preventDefault()15 queryClient.cancelQueries({ queryKey: ['todos'] })16 }}17 >18 Cancel19 </button>20)Cancel Options
取消选项用于控制查询取消操作的行为。
TypeScript
1// Cancel specific queries silently2await queryClient.cancelQueries({ queryKey: ['posts'] }, { silent: true })取消选项对象支持以下属性:
silent?: boolean- 设为
true时,将抑制CancelledError向观察者(例如onError回调)及相关通知的传播,并返回重试 Promise 而非抛出拒绝。 - 默认值为
false
- 设为
revert?: boolean- 设为
true时,将从进行中的拉取操作前一刻恢复查询状态(数据与状态),并将fetchStatus重置为idle;仅当此前无数据时才抛出错误。 - 默认值为
true
- 设为