How To Cancel Fetch Requests In React.js

Performing asynchronous operations, such as fetching data from an API, is a common task in React.js applications.

However, situations may arise where you need to cancel a fetch request, especially if the component unmounts or the user initiates another action.

In this guide, we'll explore different techniques for canceling fetch requests in React.js and ensure clean and efficient handling of asynchronous operations.

Using AbortController

The AbortController is a built-in web API that allows you to cancel asynchronous operations, including fetch requests.

It works by creating an instance of AbortController and associating it with the fetch request.

When cancellation is needed, you can call the abort method on the controller. Here's how you can implement it in a React component:

import React, { useEffect, useState } from 'react';

const MyComponent = () => {
    const [data, setData] = useState(null);
    const [loading, setLoading] = useState(true);

    useEffect(() => {
        // Create an instance of AbortController
        const controller = new AbortController();
        const signal = controller.signal;

        const fetchData = async () => {
            try {
                const response = await fetch('https://api.example.com/data', {
                    signal,
                });
                const result = await response.json();
                setData(result);
            } catch (error) {
                if (error.name === 'AbortError') {
                    console.log('Fetch request was canceled.');
                } else {
                    console.error('Error fetching data:', error);
                }
            } finally {
                // Set loading to false, regardless of success or failure
                setLoading(false);
            }
        };

        fetchData();

        // Cleanup function to abort the fetch request when the component unmounts
        return () => controller.abort();
    }, []); // Empty dependency array

    return (
        <div>
            {loading ? <p>Loading...</p> : <p>Data: {JSON.stringify(data)}</p>}
        </div>
    );
};

export default MyComponent;

In this example:

Using Custom Hooks

To make fetch cancellation more reusable, you can encapsulate the logic in a custom hook. Here's an example:

import { useEffect, useState } from 'react';

const useFetch = (url) => {
    const [data, setData] = useState(null);
    const [loading, setLoading] = useState(true);

    useEffect(() => {
        const controller = new AbortController();
        const signal = controller.signal;

        const fetchData = async () => {
            try {
                const response = await fetch(url, { signal });
                const result = await response.json();
                setData(result);
            } catch (error) {
                if (error.name === 'AbortError') {
                    console.log('Fetch request was canceled.');
                } else {
                    console.error('Error fetching data:', error);
                }
            } finally {
                setLoading(false);
            }
        };

        fetchData();

        return () => controller.abort();
    }, [url]);

    return { data, loading };
};

export default useFetch;

Now, you can use this custom hook in any component:

import React from 'react';
import useFetch from './useFetch';

const MyComponent = () => {
    const { data, loading } = useFetch('https://api.example.com/data');

    return (
        <div>
            {loading ? <p>Loading...</p> : <p>Data: {JSON.stringify(data)}</p>}
        </div>
    );
};

export default MyComponent;

This approach promotes code reusability and separation of concerns by encapsulating the fetch logic into a custom hook.

Conclusion

Canceling fetch requests in React is an essential practice to prevent unnecessary network requests and potential memory leaks. The AbortController provide reliable mechanisms for handling fetch cancellation.

By incorporating these techniques into your React components, you can ensure efficient and responsive data fetching while maintaining a clean and manageable codebase.