Cancel all subscriptions in a useEffect cleanup

After using Hooks in React, I eventually came with the following error:

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

This error occurs when React tries to set a new state of a non existing component. 😱

Meaning

Let's suppose that we write the component App.js.

jsx
import React                    from 'react';
import { Switch, Route, Link }  from 'react-router-dom';
import Hi                       from './Hi';
import Bye                      from './Bye';

const App = () => {
    
    return (
    <div className = 'App'>
        <Link to = '/hi'>Hi</Link>
        <Link to = '/bye'>Bye</Link>
        <Switch>
            <Route exact path = '/hi'  component = {Hi}/>
            <Route exact path = '/bye' component = {Bye} />
        </Switch>
    </div>
    );
}

export default App;
  • If the URL is '/hi' → Hi.js will render.
  • If the URL is '/bye' → Bye.js will render.

Hi.js displays a 'Hi Erik!' message after 5 seconds:

jsx
import React, { useEffect, useState } from 'react';

const Hi = () => {
    
    const [name, setName] = useState(null);
    
    useEffect( () => {
                
        setTimeout( () => { setName('Erik') }, 5000);
        
    }, []);
    
    return (
    <div className = 'Hi'>
        <p>Hi {name}!</p>
    </div>
    );
}

export default Hi;

Bye.js displays a 'Bye Erik!' message after 5 seconds:

jsx
import React, { useEffect, useState } from 'react';

const Bye = () => {
    
    const [name, setName] = useState(null);
    
    useEffect( () => {
                
        setTimeout( () => { setName('Erik') }, 5000);
        
    }, []);
    
    return (
    <div className = 'Bye'>
        <p>Bye {name}!</p>
    </div>
    );
}

export default Bye;

The problem

If we change from one component to the other, React will try to update the state of the old variable after 5 seconds. But the old component is not there anymore... The error will happen. 😅

React trying to update but returning an error

The solution

It's convenient to check whether the component is mounted or not before to update the state of a variable.

jsx
useEffect( () => {

    // At this point the component is mounted
    let mounted = true;
    
    // Before to set new state, check if component is mounted
    setTimeout( () => { if(mounted) setName('Erik') }, 5000);
    
    // Mounted is false when there is no component
    return () => { mounted = false };

}, []);

Hi, I'm Erik, an engineer from Barcelona. If you like the post or have any comments, say hi.