Question

How to run useEffect's cleanup function when a suspended component unmounts?

When a suspended component unmounts, useEffect's cleanup function doesn't run. This leads to memory leaks, unused event handlers, etc. This makes useEffect unintuitive to use, since we'd typically assume the cleanup function always runs when the component unmounts.

E.g. something like this:

function Foo() {
  const [isSuspended, setIsSuspended] = useState(false);

  if (isSuspended) {
    throw ...
  }

  useEffect(() => {
    window.addEventListener(...);

    return () => {
      // This doesn't run if unmounted while suspended
      window.removeEventListener(...);
    };
  }, []);

  return <button onClick={() => setIsSuspended(true)} />
}

Is there a good way to make the useEffect cleanup function run if the component was suspended before unmounting?

 3  96  3
1 Jan 1970

Solution

 0
function Foo() {
  const [isSuspended, setIsSuspended] = useState(false);
  const isMounted = useRef(true);

  // This will run the cleanup when the component unmounts
  useLayoutEffect(() => {
    return () => {
      isMounted.current = false;
    };
  }, []);

  useEffect(() => {
   window.addEventListener(...);
    return () => {
      // This cleanup will run only if the component is still mounted
      if (isMounted.current) {
        window.removeEventListener(...);
      }
    };
  }, []);

  if (isSuspended) {
   throw ...
  }

  return <button onClick={() => setIsSuspended(true)} />;
}

I am using your sample, you can refer like this.

2024-07-02
Anil Singha