框架
版本

查询取消

TanStack Query 为每个查询函数提供一个 AbortSignal 实例。当查询过时或变为非活动状态时,此 signal 将被中止。这意味着所有查询都是可取消的,并且如果需要,您可以在查询函数内部响应取消。最好的部分是,它允许您继续使用正常的 async/await 语法,同时获得自动取消的所有好处。

默认行为

默认情况下,在 Promise 解析之前卸载或变为未使用的查询不会被取消。这意味着在 Promise 解析后,结果数据将在缓存中可用。如果您已开始接收查询,但在完成之前卸载了组件,这将很有用。如果您再次挂载组件并且查询尚未被垃圾回收,则数据将可用。

但是,如果您使用了 AbortSignal,则 Promise 将被取消(例如,中止 fetch),因此,查询也必须被取消。取消查询将导致其状态恢复到其先前的状态。

使用 HttpClient

ts
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$)))
  },
}))

使用 fetch

ts
query = injectQuery(() => ({
  queryKey: ['todos'],
  queryFn: async ({ signal }) => {
    const todosResponse = await fetch('/todos', {
      // 将信号传递给一个 fetch
      signal,
    })
    const todos = await todosResponse.json()

    const todoDetails = todos.map(async ({ details }) => {
      const response = await fetch(details, {
        // 或者将其传递给多个
        signal,
      })
      return response.json()
    })

    return Promise.all(todoDetails)
  },
}))
query = injectQuery(() => ({
  queryKey: ['todos'],
  queryFn: async ({ signal }) => {
    const todosResponse = await fetch('/todos', {
      // 将信号传递给一个 fetch
      signal,
    })
    const todos = await todosResponse.json()

    const todoDetails = todos.map(async ({ details }) => {
      const response = await fetch(details, {
        // 或者将其传递给多个
        signal,
      })
      return response.json()
    })

    return Promise.all(todoDetails)
  },
}))

使用 axios

tsx
import axios from 'axios'

const query = injectQuery(() => ({
  queryKey: ['todos'],
  queryFn: ({ signal }) =>
    axios.get('/todos', {
      // 将信号传递给 `axios`
      signal,
    }),
}))
import axios from 'axios'

const query = injectQuery(() => ({
  queryKey: ['todos'],
  queryFn: ({ signal }) =>
    axios.get('/todos', {
      // 将信号传递给 `axios`
      signal,
    }),
}))

手动取消

您可能希望手动取消查询。例如,如果请求需要很长时间才能完成,您可以允许用户单击取消按钮来停止请求。为此,您只需调用 queryClient.cancelQueries({ queryKey }),这将取消查询并将其恢复到其先前的状态。如果您已使用了传递给查询函数的 signal,TanStack Query 还将额外取消 Promise。

angular-ts
@Component({
  standalone: true,
  template: `<button (click)="onCancel()">取消</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()">取消</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'])
  }
}