Query Cancellation

By default, queries that become inactive before their promises are resolved are simply ignored instead of canceled. Why is this?

  • For most applications, ignoring out-of-date queries is sufficient.
  • Cancellation APIs may not be available for every query function.
  • If cancellation APIs are available, they typically vary in implementation between utilities/libraries (eg. Fetch vs Axios vs XMLHttpRequest).

But don't worry! If your queries are high-bandwidth or potentially very expensive to download, React Query exposes a generic way to cancel query requests using a cancellation token or other related API. 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

import { CancelToken } from 'axios'
const query = useQuery('todos', () => {
// Create a new CancelToken source for this request
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

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

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 need to set the key argument of useQuery to empty string and set the enabled option to false. If promise.cancel is available, React Query will cancel the request.

const [queryKey, setQueryKey] = useState('todos')
const query = useQuery(queryKey, () => {
const controller = new AbortController()
const signal = controller.signal
const promise = fetch('/todos', {
method: 'get',
signal,
})
// Cancel the request if React Query calls the `promise.cancel` method
promise.cancel = () => controller.abort()
return promise
}, {
enabled: queryKey.length > 0
})
return (
<button onClick={(e) => {
e.preventDefault();
setQueryKey("");
}}>Cancel</button>
)
Was this page helpful?

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.