Enhance Your React App Performance with AbortController

Prashant PathakPrashant Pathak
4 min read

AbortController is an interface that allows us to abort one or more depending Web requests and allows you to cancel ongoing asynchronous operations.

To use AbortController, we can use new AbortController() constructor and it returns property instance signal and method instance abort(), although signal property it self a object constructor of AbortSignal and it have there own instance as property aborted, reason and method abort(), any(), timeout() and throwIfAborted().

The AbortController works by sending an "abort signal" that can be listened to by any function supporting abortable signals, like the fetch() function.

Why Use AbortController in React?

One scenario that requires special attention is when a component unmounts before a fetch request completes. This can lead to memory leaks or unnecessary operations, especially if you attempt to update the state of an unmounted component.

React's component lifecycle provides opportunities to manage side effects (such as data fetching) using hooks like useEffect. However, if a component is unmounted before a fetch request completes, React will attempt to update a state that no longer exists. This leads to the "memory leak" warnings that many developers encounter.

To prevent this, we can use AbortController to cancel fetch requests when the component unmounts. This ensures that no further state updates happen once the component is gone, avoiding potential bugs and improving the performance of your app.

Example: Using AbortController in a React Component

Let’s walk through a practical example where we’ll use AbortController to cancel a fetch request if a component is unmounted before the request completes.

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

const Card = (props) => {
  const [data, setData] = useState(null);
  const [error, setError] = useState(null);

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

    const fetchData = async () => {
      try {
        const response = await fetch(
          'https://jsonplaceholder.typicode.com/users',
          { signal }
        );
        if (!response.ok) {
          throw new Error('Network response was not ok');
        }
        const result = await response.json();
        setData(result);
      } catch (err) {
        if (err.name === 'AbortError') {
          console.log('Fetch aborted');
        } else {
          setError(err.message);
        }
      }
    };
    setTimeout(fetchData, 3000);
    return () => {
      controller.abort();
    };
  }, []);
  if (error) return <div>Error: {error}</div>;

  return (
    <dialog open>
      <button
        onClick={() => {
          props.close();
        }}
      >
        close
      </button>
      <p> wait for 3 sec, user list will apper</p>
      {data && (
        <div>
          <ul>{...data.map((i) => <li>{i.name}</li>)}</ul>
        </div>
      )}
    </dialog>
  );
};

export default Card;

This is Card component and here we are opening and dialog from App component. In Card, we are waiting for 3 second to make a API call so that Example will understandable. Implementation is, if you click show user button form app component that dialog will appear and after 3 second it will show you the user list. Here we are using AbortController and if you close this dialog before 3 second that means component unmounted and no need to call API, so AbortController will abort that API call with help of cleanup function.

If we will not use AbortController then the API call will happen, either component mounted or unmounted.

This cleanup function runs automatically when the component is unmounted, preventing any further state updates and avoiding potential memory leaks.

import React, { useState } from 'react';
import Card from './Card.js';

export function App(props) {
  const [show, setShow] = useState(true);
  const closeHanlde = () => {
    setShow(false);
  };
  return (
    <>
      <button onClick={() => setShow(true)}> Show Users</button>
      {show && <Card close={closeHanlde} />}
    </>
  );
}

Benefits of Using AbortController in React

Avoid Memory Leaks: By aborting ongoing fetch requests, you avoid memory leaks caused by trying to update the state of an unmounted component.

Improved Performance: Cancelling unnecessary requests reduces network load and improves application performance, especially in cases where multiple fetch requests are initiated but only the latest result is needed.

Better Error Handling: You can gracefully handle aborted requests by differentiating between an intentional abort and other network errors.

Conclusion

Using AbortController is a simple yet effective way to manage asynchronous operations in React. By integrating it into your data-fetching components, you can avoid common pitfalls like memory leaks and improve the overall reliability and performance of your application.

Next time you're working with fetch in React, consider using AbortController to make sure your app handles component unmounting gracefully!

By adopting practices like these, you ensure that your application stays performant, clean, and free from unnecessary network requests. Let me know how you implement this in your projects!

0
Subscribe to my newsletter

Read articles from Prashant Pathak directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Prashant Pathak
Prashant Pathak