Stop the Flood: Using Axios AbortController to Cancel In‑Flight Requests
When a component unmounts, its in‑flight Axios request can still finish, causing stale state updates and wasted bandwidth. This blog shows how to use Axios’s AbortController support (since 0.22.0) to cancel requests cleanly, with a React example, verification steps, and trade‑offs.
26 Mar 2026, 12:42 UTC

Why Cancelling Matters
When a user navigates away from a page or a component unmounts, the HTTP request that was started for that component can still be racing to finish. If the response finally arrives, the app may try to update state that no longer exists, or it may waste bandwidth and memory on data that the user never sees. The Axios AbortController feature lets you stop those requests cleanly.
Thesis: AbortController is the modern, lightweight way to keep UI responsive and resources tight.
Axios 0.22.0 added native support for the browser’s AbortController. By passing an AbortSignal in the request config you can cancel the request at the network layer, immediately dropping the TCP connection, and Axios will throw a CancellationError that you can catch separately from other errors.
How to Wire It Up in a React Component
- Create an
AbortControllerbefore the request. - Pass
controller.signalto Axios. - Call
controller.abort()in the cleanup function ofuseEffect. - Handle
axios.isCancelin the catch block.
Here’s a concrete example:
import { useEffect, useState } from "react";
import axios from "axios";
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const [error, setError] = useState(null);
useEffect(() => {
const controller = new AbortController();
const source = axios.CancelToken.source(); // optional, for older Axios
axios
.get(`/api/users/${userId}`, {
signal: controller.signal,
cancelToken: source.token, // keep for backward‑compatibility
})
.then((res) => setUser(res.data))
.catch((err) => {
if (axios.isCancel(err)) {
console.log("Request cancelled", err.message);
} else {
setError(err);
}
});
// Cleanup: cancel if component unmounts or userId changes
return () => {
controller.abort();
source.cancel(); // safe no‑op if already aborted
};
}, [userId]);
if (error) return <div>Error: {error.message}</div>;
if (!user) return <div>Loading…</div>;
return <div>Name: {user.name}</div>;
}
Key points:
- Use
controller.signalinstead of the oldercancelTokenif you’re on Axios ≥0.22.0. - Always catch
axios.isCancel(err)to differentiate cancellation from network or server errors. - Calling
abort()after the request has already finished does nothing, so the cleanup is safe.
Verifying Your Setup
- Check Axios version:
npm list axios # or look in package.json - Run a quick test in Node or the browser:
const controller = new AbortController(); axios.get("https://httpbin.org/delay/5", { signal: controller.signal }) .then(console.log) .catch((e) => { if (axios.isCancel(e)) console.log("Cancelled as expected"); else console.error(e); }); setTimeout(() => controller.abort(), 1000); // abort after 1s - In dev tools, start a long request and press the abort button; the network tab should show the request as cancelled and no response body.
Trade‑offs & Limitations
- Browser support: AbortController is not available in IE11 and older. If you need to support those browsers you’ll need a polyfill or fall back to
CancelToken. - Already‑completed requests: If the server has already sent a response,
abort()will not rewind the data; Axios will simply ignore the signal. - Server‑side cancellation: Cancelling on the client only stops the network transfer; the server may still finish processing the request unless it also checks for client disconnects.
- Error handling: Remember to catch
axios.isCancelerrors; otherwise they may surface as unhandled rejections in the console.
Actionable Takeaway
Upgrade to Axios ≥0.22.0, replace any CancelToken usage with AbortController, and tie the controller to component lifecycles. This will:
- Prevent race conditions when components unmount.
- Reduce bandwidth and memory usage on the client.
- Improve user experience by avoiding flickering or stale data.
Give it a try in your next fetch‑heavy component and feel the difference.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.