Correct way to handle API requests in a useEffect hook

elishaking

King Elisha

Posted on September 15, 2022

Correct way to handle API requests in a useEffect hook

It is common to issue an asynchronous request to an API in a useEffect hook. Perhaps to fetch some data which is eventually used to update component state. Something like this:

const [data, setData] = useState([]);

useEffect(() => {
  axios.get('get/some/data').then(({ data }) => {
    setData(data);
  });
}, []);
Enter fullscreen mode Exit fullscreen mode

It is also common to encounter a situation where the component unmounts before the request is complete. The callback will still be executed if the component unmounts because the request was not cancelled. Consequently, when setData is called, this interesting warning pops up in the browser console:

Warning: Can’t perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.

How to fix this

To fix this, the request needs to be cancelled when the component unmounts (in the useEffect cleanup function). This can be easily achieved with axios as follows:

const [data, setData] = useState([]);

useEffect(() => {
  const cancelToken = axios.CancelToken.source();

  axios
    .get('get/some/data', { cancelToken: cancelToken.token })
    .then(({ data }) => {
      setData(data);
    })
    .catch((err) => {
      if (axios.isCancel(err)) {
        // TODO
      }
    });

  return () => {
    cancelToken.cancel();
  };
}, []);
Enter fullscreen mode Exit fullscreen mode

This can also be accomplished with fetch using AbortController as follows:

const [data, setData] = useState([]);

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

  fetch('get/some/data', { signal: controller.signal })
    .then((res) => res.json())
    .then((data) => {
      setData(data);
    })
    .catch((err) => {
      if (err.name === 'AbortError') {
        // TODO
      }
    });

  return () => {
    controller.abort();
  };
}, []);
Enter fullscreen mode Exit fullscreen mode
💖 💪 🙅 🚩
elishaking
King Elisha

Posted on September 15, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related