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?
Answer
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.