← Posts

Prevent state updates on unmounted React components

Today I was writing a test and encountered the following error message while in my test runner:

  console.error
    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.

The code I was testing looked like this:

React.useEffect(() => {
  dispatch({ type: "LOADING" });
  axios
    .get(`/api/v1/posts`)
    .then((res) => {
      dispatch({ type: "SUCCESS", payload: res.data });
    })
    .catch((error) => {
      dispatch({ type: "ERROR", error });
    });
}, []);

The problem is that my tests were running too quickly and causing the component to unmount by the time dispatch was getting called. The easiest way to fix this issue is to set a mounted variable that is updated when this component is unmounted:

React.useEffect(() => {
  // successful mount
  let mounted = true;

  dispatch({ type: "LOADING" });
  axios
    .get(`/api/v1/posts`)
    .then((res) => {
      // avoids calling this when we've unmounted
      if (mounted) {
        dispatch({ type: "SUCCESS", payload: res.data });
      }
    })
    .catch((error) => {
      // avoids calling this when we've unmounted
      if (mounted) {
        dispatch({ type: "ERROR", error });
      }
    });

  // called on unmount
  return () => (mounted = false);
}, []);