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 allows 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.
By default, queries that unmount or become unused before their promises are resolved are not cancelled. This means that after the promise has resolved, the resulting data will be available in the cache. This is helpful if you've started receiving a query, but then unmount the component before it finishes. If you mount the component again and the query has not been garbage collected yet, data will be available.
However, if you consume the AbortSignal
or attach a cancel
function to your Promise, the Promise will be cancelled (e.g. aborting the fetch) and therefore, also the Query must be cancelled. Cancelling the query will result in its state being reverted to its previous state.
fetch
const query = useQuery('todos', async ({ signal }) => {const todosResponse = await fetch('/todos', {// Pass the signal to one fetchsignal,})const todos = await todosResponse.json()const todoDetails = todos.map(async ({ details } => {const response = await fetch(details, {// Or pass it to severalsignal,})return response.json()})return Promise.all(todoDetails)})
axios
axios
v0.22.0+import axios from 'axios'const query = useQuery('todos', ({ signal }) =>axios.get('/todos', {// Pass the signal to `axios`signal,}))
axios
version less than v0.22.0import axios from 'axios'const query = useQuery('todos', ({ signal }) => {// Create a new CancelToken source for this requestconst CancelToken = axios.CancelTokenconst source = CancelToken.source()const promise = axios.get('/todos', {// Pass the source token to your requestcancelToken: source.token,})// Cancel the request if React Query signals to abortsignal?.addEventListener('abort', () => {source.cancel('Query was cancelled by React Query')})return promise})
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()})})
graphql-request
An AbortSignal
can be set in the client request
method.
const client = new GraphQLClient(endpoint)const query = useQuery('todos', ({ signal }) => {client.request({ document: query, signal })})
graphql-request
version less than v4.0.0An AbortSignal
can be set in the GraphQLClient
constructor.
const query = useQuery('todos', ({ signal }) => {const client = new GraphQLClient(endpoint, {signal,});return client.request(query, variables)})
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)
, which will cancel the query and revert it back to its previous state. If promise.cancel
is available, or you have consumed the signal
passed to the query function, React Query will additionally also cancel the Promise.
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>)
cancel
functionDon'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 standardized 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).
axios
with cancel
functionimport axios from 'axios'const query = useQuery('todos', () => {// Create a new CancelToken source for this requestconst CancelToken = axios.CancelTokenconst source = CancelToken.source()const promise = axios.get('/todos', {// Pass the source token to your requestcancelToken: source.token,})// Cancel the request if React Query calls the `promise.cancel` methodpromise.cancel = () => {source.cancel('Query was cancelled by React Query')}return promise})
fetch
with cancel
functionconst query = useQuery('todos', () => {// Create a new AbortController instance for this requestconst controller = new AbortController()// Get the abortController's signalconst signal = controller.signalconst promise = fetch('/todos', {method: 'get',// Pass the signal to your requestsignal,})// Cancel the request if React Query calls the `promise.cancel` methodpromise.cancel = () => controller.abort()return promise})
The best JavaScript newsletter! Delivered every Monday to over 76,000 devs.