Why Can’t My Component Unmount in React?
Fixing a common React race condition

Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
Sometimes, I read a warning and have absolutely no idea what it’s trying to tell me.
Let’s start with the first phrase: “Can’t perform a React state update on an unmounted component.” State updates are scattered in every component I build. The curious part is that one of these components is unmounted.
How is this possible? Most updates that occur in my code “react” to a user action. For instance, a button click:
The setter function provided by useState
can either be passed a value or a function whose first argument is the current value.
Obviously, handleLoad
can only be called when the button is mounted and rendered. I’ll never encounter the warning with this code.
I still haven’t gotten anywhere. Reading the third sentence gives me a better hint. React is telling me to ensure that any subscription or asynchronous task was cancelled. The next step, then, is looking for asynchronous tasks!
3 Offenders
I find three offenders when I encounter this problem: an async function, a state change dependent on that function, and an unmount
event.
To triage the warning, I’ll set up a component for reference. It has one state variable:
function UnmountComponent() {
const [count, setCount] = useState(0);
...
The first offender I’ll deal with is an async function. It mimics loading some remote resource. It might be an axios or fetch call. It completes after two seconds.
This function is not in a React component:
function load() {
return new Promise(res => {
setTimeout(res, 2000);
});
}
Next, a criminal dependency. It’s a function that attempts to modify my React component’s state:
Finally, we need an unmount
event. One use case would be loading the remote resource and then navigating away from the route. In my example, I wrapped the breaking component in a higher-level one. This higher-level component simply unmounts the breaking component on a button press:
The warning is a race condition. The first step is to click the AsyncCount
button in the following code:
Then, while the remote resource is loading, click on the Unmount
button. When I open up the console, I can see the warning!
This happens because setCount
is called after the remote resource completed (load().then)
but also after the component unmounted.
Conclusion
You’re going to encounter this if you depend on promises and enable React.StrictMode
. It’s simply a race condition where your component unmounts while a remote resource is loading. One solution is to bring the remote resource call into a useEffect
and listen for the unmount event:
The return function is called only when the component unmounts because it has no other dependencies.
I built the previous example in CodeSandbox. Feel free to run it with the reproduction steps to see the error.