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.

Die AbortController-API ist in den meisten Laufzeitumgebungen verfügbar. Wenn Ihre Laufzeitumgebung sie nicht unterstützt, müssen Sie ein Polyfill bereitstellen. Es gibt mehrere verfügbare.

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 fetch

tsx
const query = useQuery({
  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)
  },
})
const query = useQuery({
  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 v0.22.0+

tsx
import axios from 'axios'

const query = useQuery({
  queryKey: ['todos'],
  queryFn: ({ signal }) =>
    axios.get('/todos', {
      // Pass the signal to `axios`
      signal,
    }),
})
import axios from 'axios'

const query = useQuery({
  queryKey: ['todos'],
  queryFn: ({ signal }) =>
    axios.get('/todos', {
      // Pass the signal to `axios`
      signal,
    }),
})

Verwendung von axios mit Versionen kleiner als v0.22.0

tsx
import axios from 'axios'

const query = useQuery({
  queryKey: ['todos'],
  queryFn: ({ signal }) => {
    // Create a new CancelToken source for this request
    const CancelToken = axios.CancelToken
    const source = CancelToken.source()

    const promise = axios.get('/todos', {
      // Pass the source token to your request
      cancelToken: source.token,
    })

    // Cancel the request if TanStack Query signals to abort
    signal?.addEventListener('abort', () => {
      source.cancel('Query was cancelled by TanStack Query')
    })

    return promise
  },
})
import axios from 'axios'

const query = useQuery({
  queryKey: ['todos'],
  queryFn: ({ signal }) => {
    // Create a new CancelToken source for this request
    const CancelToken = axios.CancelToken
    const source = CancelToken.source()

    const promise = axios.get('/todos', {
      // Pass the source token to your request
      cancelToken: source.token,
    })

    // Cancel the request if TanStack Query signals to abort
    signal?.addEventListener('abort', () => {
      source.cancel('Query was cancelled by TanStack Query')
    })

    return promise
  },
})

Verwendung von XMLHttpRequest

tsx
const query = useQuery({
  queryKey: ['todos'],
  queryFn: ({ signal }) => {
    return new Promise((resolve, reject) => {
      var oReq = new XMLHttpRequest()
      oReq.addEventListener('load', () => {
        resolve(JSON.parse(oReq.responseText))
      })
      signal?.addEventListener('abort', () => {
        oReq.abort()
        reject()
      })
      oReq.open('GET', '/todos')
      oReq.send()
    })
  },
})
const query = useQuery({
  queryKey: ['todos'],
  queryFn: ({ signal }) => {
    return new Promise((resolve, reject) => {
      var oReq = new XMLHttpRequest()
      oReq.addEventListener('load', () => {
        resolve(JSON.parse(oReq.responseText))
      })
      signal?.addEventListener('abort', () => {
        oReq.abort()
        reject()
      })
      oReq.open('GET', '/todos')
      oReq.send()
    })
  },
})

Verwendung von graphql-request

Ein AbortSignal kann in der Client-Methode request gesetzt werden.

tsx
const client = new GraphQLClient(endpoint)

const query = useQuery({
  queryKey: ['todos'],
  queryFn: ({ signal }) => {
    client.request({ document: query, signal })
  },
})
const client = new GraphQLClient(endpoint)

const query = useQuery({
  queryKey: ['todos'],
  queryFn: ({ signal }) => {
    client.request({ document: query, signal })
  },
})

Verwendung von graphql-request mit Versionen kleiner als v4.0.0

Ein AbortSignal kann im Konstruktor von GraphQLClient gesetzt werden.

tsx
const query = useQuery({
  queryKey: ['todos'],
  queryFn: ({ signal }) => {
    const client = new GraphQLClient(endpoint, {
      signal,
    })
    return client.request(query, variables)
  },
})
const query = useQuery({
  queryKey: ['todos'],
  queryFn: ({ signal }) => {
    const client = new GraphQLClient(endpoint, {
      signal,
    })
    return client.request(query, variables)
  },
})

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.

tsx
const query = useQuery({
  queryKey: ['todos'],
  queryFn: async ({ signal }) => {
    const resp = await fetch('/todos', { signal })
    return resp.json()
  },
})

const queryClient = useQueryClient()

return (
  <button
    onClick={(e) => {
      e.preventDefault()
      queryClient.cancelQueries({ queryKey: ['todos'] })
    }}
  >
    Cancel
  </button>
)
const query = useQuery({
  queryKey: ['todos'],
  queryFn: async ({ signal }) => {
    const resp = await fetch('/todos', { signal })
    return resp.json()
  },
})

const queryClient = useQueryClient()

return (
  <button
    onClick={(e) => {
      e.preventDefault()
      queryClient.cancelQueries({ queryKey: ['todos'] })
    }}
  >
    Cancel
  </button>
)

Abbruch-Optionen

Abbruch-Optionen werden verwendet, um das Verhalten von Query-Abbruchvorgängen zu steuern.

tsx
// Cancel specific queries silently
await queryClient.cancelQueries({ queryKey: ['posts'] }, { silent: true })
// Cancel specific queries silently
await queryClient.cancelQueries({ queryKey: ['posts'] }, { silent: true })

Ein Objekt für Abbruch-Optionen unterstützt die folgenden Eigenschaften

  • silent?: boolean
    • Wenn auf true gesetzt, unterdrückt die Weitergabe von CancelledError an Beobachter (z. B. onError-Callbacks) und zugehörige Benachrichtigungen und gibt das Retry-Promise zurück, anstatt abzulehnen.
    • Standardmäßig false
  • revert?: boolean
    • Wenn auf true gesetzt, wird der Zustand der Query (Daten und Status) von unmittelbar vor dem laufenden Fetch wiederhergestellt, der fetchStatus auf idle zurückgesetzt und nur dann ein Fehler ausgelöst, wenn keine vorherigen Daten vorhanden waren.
    • Standardmäßig true

Einschränkungen

Der Abbruch funktioniert nicht, wenn mit Suspense-Hooks gearbeitet wird: useSuspenseQuery, useSuspenseQueries und useSuspenseInfiniteQuery.