Query Cancellation

Previous method requiring a cancel function

React Query provides each query function with an AbortSignal instance if it's available in your runtime environment. When a query becomes out-of-date or inactive, this signal will become aborted. This means that all queries are cancellable and you can respond to the cancellation inside your query function if desired. The best part about this is that it allow you to continue to use normal async/await syntax while getting all the benefits of automatic cancellation. Additionally, this solution works better with TypeScript than the old solution.

The AbortController API is available in most runtime environments, but if the runtime environment does not support it then the query function will receive undefined in its place. You may choose to polyfill the AbortController API if you wish, there are several available.

NOTE: This feature was introduced at version 3.30.0. If you are using an older version, you will need to either upgrade (recommended) or use the old cancel function.

Using fetch

const query = useQuery('todos', 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)
})

Using axios

Using axios v0.22.0+

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

Using an axios version less than v0.22.0

import axios from 'axios'
const query = useQuery('todos', ({ 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 React Query signals to abort
signal?.addEventListener('abort', () => {
source.cancel('Query was cancelled by React Query')
})
return promise
})

Using XMLHttpRequest

const query = useQuery('todos', ({ 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()
})
})

Manual Cancellation

You might want to cancel a query manually. For example, if the request takes a long time to finish, you can allow the user to click a cancel button to stop the request. To do this, you just need to call queryClient.cancelQueries(key). If promise.cancel is available or you have consumed the signal passed to the query function then React Query will cancel the request.

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

Old cancel function

Don't worry! The previous cancellation functionality will continue to work. But we do recommend that you move away from the withdrawn cancelable promise proposal to the new AbortSignal interface which has been stardardized as a general purpose construct for aborting ongoing activities in most browsers and in Node. The old cancel function might be removed in a future major version.

To integrate with this feature, attach a cancel function to the promise returned by your query that implements your request cancellation. When a query becomes out-of-date or inactive, this promise.cancel function will be called (if available).

Using axios with cancel function

import axios from 'axios'
const query = useQuery('todos', () => {
// 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 React Query calls the `promise.cancel` method
promise.cancel = () => {
source.cancel('Query was cancelled by React Query')
}
return promise
})

Using fetch with cancel function

const query = useQuery('todos', () => {
// Create a new AbortController instance for this request
const controller = new AbortController()
// Get the abortController's signal
const signal = controller.signal
const promise = fetch('/todos', {
method: 'get',
// Pass the signal to your request
signal,
})
// Cancel the request if React Query calls the `promise.cancel` method
promise.cancel = () => controller.abort()
return promise
})
Was this page helpful?

Resources

Subscribe to our newsletter

The latest TanStack news, articles, and resources, sent to your inbox.

    I won't send you spam.

    Unsubscribe at any time.

    © 2020 Tanner Linsley. All rights reserved.