

AbortController when doing Fetch API
If you're accustomed to using the Fetch API in React (or Preact), you're likely familiar with the following code structure.
const Home = () => {
const [users, setUsers] = useState([]);
const [error, setError] = useState("");
useEffect(() => {
const endpoint = "https://jsonplaceholder.typicode.com/users";
fetch(endpoint).then(response => {
return response.json();
}).then(newUsers => {
setUsers(newUsers);
}).catch(({message}) => {
setError(message);
});
}, []);
return ({users.map(({username}, key) => ({ username }))});
};
However, what occurs when your network connection suddenly slows down? Perhaps the network response is delayed, prompting you to navigate to another page.
Coincidentally, at that very moment, on a separate page, you initiate another request using the same pattern. Consequently, you find yourself with two simultaneous requests vying for the limited network bandwidth.
Naturally, you begin to question: is my network experiencing issues? To investigate, you attempt to access another page with the same pattern, further burdening the server with three concurrent connections over a sluggish network.
Fortunately, this issue can be easily addressed by employing an AbortController
.
const Home = () => {
const [users, setUsers] = useState([]);
const [error, setError] = useState("");
useEffect(() => {
const endpoint = "https://jsonplaceholder.typicode.com/users";
// Instanciation of our controller
const controller = new AbortController();
// Attaching the signal to the request
fetch(endpoint, {signal: controller.signal}).then(response => {
return response.json();
}).then(newUsers => {
setUsers(newUsers);
}).catch(({message}) => {
setError(message);
});
// Canceling the request when the component is destroyed
return () => controller.abort();
}, []);
return ({users.map(({username}, key) => ({ username }))});
};
I've inserted a comment above the new additions. These three lines suffice to prevent background requests from overwhelming the network unnecessarily.
Now, whenever a user navigates to another page, the cleanup function triggers, halting the request via the abort controller. This action conserves valuable bandwidth for subsequent requests, hopefully ensuring success.
Interestingly, the same principle applies to Vue.js, where you can invoke the controller within the destroyed
lifecycle method in Vue 2 and onBeforeUnmount
in Vue 3.
This is sample code which using Vue 3:
import { ref, onBeforeUnmount } from 'vue';
const endpoint = "https://jsonplaceholder.typicode.com/users";
const controller = new AbortController();
const error = ref("");
const users = ref([]);
fetch(endpoint, { signal: controller.signal })
.then(response => response.json())
.then(newUsers => users.value = newUsers)
.catch(({ message }) => error.value = message);
onBeforeUnmount(() => {
controller.abort();
});
Thanks for reading!
Related Blogs
















