How to fix Cannot update state on unmounted component. This is a no-op, but it indicates a memory leak in React

ReactINTERMEDIATEMEDIUMUpdated Dec 10, 2025ยท 118 views

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;
  };
}, []);
  1. Add a cleanup function to your useEffect
  2. Cancel pending promises with AbortController
  3. Clear timers and intervals
  4. Unsubscribe from event listeners and subscriptions
react โ€” error
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

  1. Not cleaning up asynchronous operations in the useEffect cleanup function
  2. Calling setState after an async operation completes without checking if the component is still mounted
  3. Using setTimeout or setInterval without clearing them when the component unmounts
  4. Subscribing to event listeners, WebSocket connections, or observables without unsubscribing
  5. 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"

1Add a cleanup function to your useEffect

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.

javascript
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.

2Cancel pending promises with AbortController

For fetch requests, use AbortController to cancel pending network requests when the component unmounts.

javascript
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.

3Clear timers and intervals

Always clear setTimeout and setInterval in your cleanup function.

javascript
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.

4Unsubscribe from event listeners and subscriptions

If you subscribe to events, WebSockets, or observables, unsubscribe in the cleanup.

javascript
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.

5Use useRef for mounting status in complex scenarios

For more complex scenarios where you need to track mount status across multiple effects, consider using useRef.

javascript
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.

Official resources & further reading