TanStack Query 为每个查询函数提供一个 AbortSignal 实例。当查询过期或变得不活跃时,此 信号将被中止。这意味着所有查询都是可取消的,并且您可以根据需要响应查询函数内的取消。关于这一点最好的地方在于,它允许您在获得自动取消的所有好处的同时,继续使用正常的 async/await 语法。
默认情况下,在 Promise 解析之前卸载或变得未使用的查询 *不会* 被取消。这意味着在 Promise 解析后,返回的数据将在缓存中可用。如果您启动了一个查询,但在它完成之前卸载了组件,这将非常有用。如果您再次挂载组件并且查询尚未被垃圾回收,数据将可用。
但是,如果您使用了 AbortSignal,Promise 将被取消(例如,中止 fetch 请求),因此,查询也必须被取消。取消查询将导致其状态 *恢复* 到之前的状态。
import { HttpClient } from '@angular/common/http'
import { injectQuery } from '@tanstack/angular-query-experimental'
postQuery = injectQuery(() => ({
enabled: this.postId() > 0,
queryKey: ['post', this.postId()],
queryFn: async (context): Promise<Post> => {
const abort$ = fromEvent(context.signal, 'abort')
return lastValueFrom(this.getPost$(this.postId()).pipe(takeUntil(abort$)))
},
}))
import { HttpClient } from '@angular/common/http'
import { injectQuery } from '@tanstack/angular-query-experimental'
postQuery = injectQuery(() => ({
enabled: this.postId() > 0,
queryKey: ['post', this.postId()],
queryFn: async (context): Promise<Post> => {
const abort$ = fromEvent(context.signal, 'abort')
return lastValueFrom(this.getPost$(this.postId()).pipe(takeUntil(abort$)))
},
}))
query = injectQuery(() => ({
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)
},
}))
query = injectQuery(() => ({
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 = injectQuery(() => ({
queryKey: ['todos'],
queryFn: ({ signal }) =>
axios.get('/todos', {
// Pass the signal to `axios`
signal,
}),
}))
import axios from 'axios'
const query = injectQuery(() => ({
queryKey: ['todos'],
queryFn: ({ signal }) =>
axios.get('/todos', {
// Pass the signal to `axios`
signal,
}),
}))
您可能希望手动取消查询。例如,如果请求花费很长时间才能完成,您可以允许用户单击取消按钮来停止请求。为此,您只需调用 queryClient.cancelQueries({ queryKey }),这将取消查询并将其恢复到之前的状态。如果您使用了传递给查询函数的 signal,TanStack Query 还会额外取消 Promise。
@Component({
standalone: true,
template: `<button (click)="onCancel()">Cancel</button>`,
})
export class TodosComponent {
query = injectQuery(() => ({
queryKey: ['todos'],
queryFn: async ({ signal }) => {
const resp = await fetch('/todos', { signal })
return resp.json()
},
}))
queryClient = inject(QueryClient)
onCancel() {
this.queryClient.cancelQueries(['todos'])
}
}
@Component({
standalone: true,
template: `<button (click)="onCancel()">Cancel</button>`,
})
export class TodosComponent {
query = injectQuery(() => ({
queryKey: ['todos'],
queryFn: async ({ signal }) => {
const resp = await fetch('/todos', { signal })
return resp.json()
},
}))
queryClient = inject(QueryClient)
onCancel() {
this.queryClient.cancelQueries(['todos'])
}
}