How to fix Cannot update state on unmounted component. This is a no-op, but it indicates a memory leak in React
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.
Quick fix
Fixes Cannot update state on unmounted component. This is a no-op, but it indicates a memory leak
useEffect(() => {
let isMounted = true;
const fetchData = async () => {
const data = await someAsyncOperation();
if (isMounted) {
setState(data);
}
};
fetchData();
return () => {
isMounted = false;
};
}, []);- Add a cleanup function to your useEffect
- Cancel pending promises with AbortController
- Clear timers and intervals
- Unsubscribe from event listeners and subscriptions
useEffect(() => {let isMounted = true;const fetchData = async () => {const data = await someAsyncOperation();if (isMounted) {setState(data);}};fetchData();return () => {isMounted = false;};}, []);Cannot update state on unmounted component. This is a no-op, but it indicates a memory leak
What this error means
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.
Typical symptoms
- You see the warning 'Cannot update state on unmounted component' in your browser's console during development
- The application works but you notice performance degradation over time, especially with frequent component mounts/unmounts
- Network requests or other async operations continue running in the background after navigating away from a page
- Memory usage gradually increases when using features that involve rapid component mounting/unmounting
Common causes
- Not cleaning up asynchronous operations in the useEffect cleanup function
- Calling setState after an async operation completes without checking if the component is still mounted
- Using setTimeout or setInterval without clearing them when the component unmounts
- Subscribing to event listeners, WebSocket connections, or observables without unsubscribing
- Fetching data in componentDidMount (class components) or useEffect without cancellation support
How to fix "Cannot update state on unmounted component. This is a no-op, but it indicates a memory leak"
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.
Advanced notes
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.
Frequently asked questions
- What does "Cannot update state on unmounted component. This is a no-op, but it in" mean?
- 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.
- How do I fix "Cannot update state on unmounted component. This is a no-op, but it in"?
- 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.
- What causes "Cannot update state on unmounted component. This is a no-op, but it in"?
- Not cleaning up asynchronous operations in the useEffect cleanup function Calling setState after an async operation completes without checking if the component is still mounted Using setTimeout or setInterval without clearing them when the component unmounts
- Is the "Cannot update state on unmounted component. This is a no-op, but it in" error serious?
- It is a medium-severity error โ more of a blocker than a risk. The steps above resolve it.