This React warning occurs when you attempt to update a component's state after it has been unmounted from the DOM. It's a common issue in applications with asynchronous operations like API calls, timers, or event listeners that haven't been properly cleaned up. Fixing it prevents memory leaks and ensures your application behaves correctly.
The "Cannot update state on unmounted component" warning is React's way of telling you that your code is trying to update the state of a component that is no longer part of the DOM tree. This typically happens when an asynchronous operation (like a fetch request, setTimeout, or subscription) completes after the component has been unmounted. When a component unmounts, React cleans up its resources, but if you have pending asynchronous tasks that call setState when they resolve, those state updates are unnecessary and can cause memory leaks because they keep references to the component in memory. While React prevents the actual update (making it a "no-op"), the warning indicates a potential resource leak that could affect your application's performance over time. This warning is especially common in components that fetch data on mount and don't cancel pending requests when unmounting, or in components that set up timers or event listeners without proper cleanup.
In functional components, always return a cleanup function from your useEffect hook. This function runs when the component unmounts or before the effect runs again.
useEffect(() => {
let isMounted = true;
const fetchData = async () => {
const data = await someAsyncOperation();
if (isMounted) {
setState(data);
}
};
fetchData();
return () => {
isMounted = false;
};
}, []);The isMounted flag prevents state updates after unmounting.
For fetch requests, use AbortController to cancel pending network requests when the component unmounts.
useEffect(() => {
const controller = new AbortController();
const signal = controller.signal;
fetch('/api/data', { signal })
.then(response => response.json())
.then(data => {
if (!signal.aborted) {
setData(data);
}
})
.catch(error => {
if (error.name !== 'AbortError') {
console.error('Fetch error:', error);
}
});
return () => {
controller.abort();
};
}, []);This approach ensures network requests are cancelled when they're no longer needed.
Always clear setTimeout and setInterval in your cleanup function.
useEffect(() => {
const timerId = setTimeout(() => {
setState('Timeout completed');
}, 5000);
const intervalId = setInterval(() => {
setCount(prev => prev + 1);
}, 1000);
return () => {
clearTimeout(timerId);
clearInterval(intervalId);
};
}, []);This prevents timers from firing after component unmount.
If you subscribe to events, WebSockets, or observables, unsubscribe in the cleanup.
useEffect(() => {
const handleResize = () => {
setWindowSize({
width: window.innerWidth,
height: window.innerHeight
});
};
window.addEventListener('resize', handleResize);
// For RxJS subscriptions
const subscription = someObservable$.subscribe(data => {
setData(data);
});
return () => {
window.removeEventListener('resize', handleResize);
subscription.unsubscribe();
};
}, []);Proper cleanup prevents memory leaks from lingering subscriptions.
For more complex scenarios where you need to track mount status across multiple effects, consider using useRef.
function MyComponent() {
const isMountedRef = useRef(true);
useEffect(() => {
isMountedRef.current = true;
someAsyncOperation().then(data => {
if (isMountedRef.current) {
setState(data);
}
});
return () => {
isMountedRef.current = false;
};
}, []);
// ... rest of component
}This pattern is useful when you have multiple async operations in the same component.
React's Strict Mode helps identify these issues during development by intentionally mounting and unmounting components twice. This makes the warning appear more frequently, helping you catch cleanup problems early.
For class components, you can use the _isMounted pattern (though it's considered an anti-pattern in modern React). Instead, consider migrating to functional components with hooks, which provide more straightforward cleanup mechanisms.
Some libraries provide built-in cancellation support. For example, Axios has CancelToken, and many state management libraries (like Redux Toolkit Query) handle cleanup automatically.
Remember that while preventing this warning is important for code quality, React itself prevents the actual state update when a component is unmounted. The primary concern is avoiding memory leaks and unnecessary work.
React Hook useCallback has a missing dependency: 'variable'. Either include it or remove the dependency array react-hooks/exhaustive-deps
React Hook useCallback has a missing dependency
Cannot use private fields in class components without TS support
Cannot use private fields in class components without TS support
Cannot destructure property 'xxx' of 'undefined'
Cannot destructure property of undefined when accessing props
useNavigate() may be used only in the context of a <Router> component.
useNavigate() may be used only in the context of a Router component
Cannot find module or its corresponding type declarations
How to fix "Cannot find module or type declarations" in Vite