查询取消
TanStack Query 会为每个查询函数提供一个 AbortSignal 实例。当查询变为过期或非活跃状态时,该 signal 将被中止。这意味着所有查询均可取消,且你可根据需要在查询函数内部响应取消操作。最棒之处在于,你得以继续使用常规的 async/await 语法,同时获得自动取消的所有优势。
默认行为
默认情况下,若查询在 Promise 解析完成前已卸载(unmount)或不再被使用,则 不会 被取消。这意味着一旦 Promise 解析完成,所得数据将存入缓存。当你已发起某个查询,但组件在查询完成前即被卸载时,此行为十分有用:若之后再次挂载该组件,且该查询尚未被垃圾回收,则数据仍可立即使用。
然而,若你在查询函数中使用了 AbortSignal,则 Promise 将被取消(例如中止 fetch 请求),因此该查询也必须被取消。取消查询会导致其状态 回滚 至此前状态。
使用 HttpClient
TypeScript
1import { injectQuery } from '@tanstack/angular-query-experimental'2import { fromEvent, lastValueFrom, takeUntil } from 'rxjs'3 4postQuery = injectQuery(() => ({5 queryKey: ['post', this.postId()],6 queryFn: (context): Promise<Post> => {7 const abort$ = fromEvent(context.signal, 'abort')8 return lastValueFrom(this.getPost$(this.postId()).pipe(takeUntil(abort$)))9 },10}))使用 fetch
TypeScript
1todosQuery = injectQuery(() => ({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
TypeScript
1import axios from 'axios'2 3const todosQuery = injectQuery(() => ({4 queryKey: ['todos'],5 queryFn: ({ signal }) =>6 axios.get('/todos', {7 // Pass the signal to `axios`8 signal,9 }),10}))手动取消
你可能需要手动取消某个查询。例如,若请求耗时较长,你可以允许用户点击取消按钮来中止请求。为此,只需调用 queryClient.cancelQueries({ queryKey }),该方法将取消查询并使其状态回滚至此前状态。若你已在查询函数中使用了传入的 signal,TanStack Query 还会额外取消该 Promise。
angular-ts
1@Component({2 template: `<button (click)="onCancel()">Cancel</button>`,3})4export class TodosComponent {5 readonly todosQuery = injectQuery(() => ({6 queryKey: ['todos'],7 queryFn: async ({ signal }) => {8 const resp = await fetch('/todos', { signal })9 return resp.json()10 },11 }))12 13 readonly queryClient = inject(QueryClient)14 15 onCancel() {16 this.queryClient.cancelQueries({ queryKey: ['todos'] })17 }18}