Framework
Version

Query-Abbruch

TanStack Query stellt jeder Query-Funktion eine AbortSignal-Instanz zur Verfügung. Wenn eine Query veraltet oder inaktiv wird, wird dieses Signal abgebrochen. Das bedeutet, dass alle Queries abgebrochen werden können, und Sie können bei Bedarf auf den Abbruch innerhalb Ihrer Query-Funktion reagieren. Das Beste daran ist, dass Sie weiterhin die normale async/await-Syntax verwenden können und gleichzeitig alle Vorteile des automatischen Abbruchs nutzen.

Standardverhalten

Standardmäßig werden Queries, die vor der Auflösung ihrer Promises ausgemountet oder ungenutzt werden, *nicht* abgebrochen. Das bedeutet, dass nach der Auflösung des Promises die resultierenden Daten im Cache verfügbar sind. Dies ist hilfreich, wenn Sie mit dem Empfang einer Query begonnen haben, aber die Komponente vor Abschluss ausgemountet haben. Wenn Sie die Komponente erneut mounten und die Query noch nicht aus dem Garbage Collector entfernt wurde, sind die Daten verfügbar.

Wenn Sie jedoch das AbortSignal verbrauchen, wird das Promise abgebrochen (z. B. das Abbrechen des Fetch) und daher muss auch die Query abgebrochen werden. Das Abbrechen der Query führt dazu, dass ihr Status auf ihren vorherigen Zustand *zurückgesetzt* wird.

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

Verwendung von fetch

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

Verwendung von axios

tsx
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,
    }),
}))

Manuelles Abbrechen

Möglicherweise möchten Sie eine Query manuell abbrechen. Wenn eine Anfrage beispielsweise lange dauert, können Sie dem Benutzer ermöglichen, auf eine Abbrechen-Schaltfläche zu klicken, um die Anfrage zu stoppen. Dazu müssen Sie nur queryClient.cancelQueries({ queryKey }) aufrufen. Dies bricht die Query ab und setzt sie in ihren vorherigen Zustand zurück. Wenn Sie das an die Query-Funktion übergebene Signal verbraucht haben, wird TanStack Query zusätzlich auch das Promise abbrechen.

angular-ts
@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'])
  }
}