Can't perform a react state update on an unmounted component

avatar

Borislav Hadzhiev

Thu Apr 28 20222 min read

Can't perform a react state update on an unmounted component #

To solve the "Warning: Can't perform a React state update on an unmounted component", declare an isMounted boolean in your useEffect hook that is used to track whether the component is mounted. A component's state should only be updated if the component is mounted.

App.js
import {useState, useEffect} from 'react'; const App = () => { const [state, setState] = useState(''); useEffect(() => { // 👇️ set isMounted to true let isMounted = true; async function fetchData() { const result = await Promise.resolve(['hello', 'world']); // 👇️ only update state if component is mounted if (isMounted) { setState(result); } } fetchData(); return () => { // 👇️ when component unmounts, set isMounted to false isMounted = false; }; }, []); return ( <div> <h2>State: {JSON.stringify(state)}</h2> </div> ); }; export default App;
The warning "Can't perform a React state update on an unmounted component" is caused when we try to update the state of an unmounted component.

A straight forward way to get rid of the warning is to keep track of whether the component is mounted using an isMounted boolean in our useEffect hook.

We initialized the isMounted boolean to true in useEffect.

Our fetchData function performs some async task, most commonly an API request and updates the state based on the response.

However, note that we only update the state if the isMounted variable is set to true.

App.js
async function fetchData() { const result = await Promise.resolve(['hello', 'world']); // 👇️ only update state if component is mounted if (isMounted) { setState(result); } }

This helps us avoid the warning because we aren't updating the state if the component isn't mounted.

The function we returned from the useEffect hook is called when the component unmounts.

App.js
return () => { // 👇️ when component unmounts, set isMounted to false isMounted = false; };

We set the isMounted variable to false to indicate that the component is no longer mounted.

If our fetchData function is invoked after the component unmounts, the if block won't run because isMounted is set to false.

App.js
async function fetchData() { const result = await Promise.resolve(['hello', 'world']); // 👇️ only update state if component is mounted if (isMounted) { setState(result); } }

If you do this often, you can extract the logic into a reusable hook.

App.js
import {useState, useEffect, useRef} from 'react'; // 👇️ extract logic into reusable hook function useIsMounted() { const isMounted = useRef(false); useEffect(() => { isMounted.current = true; return () => { isMounted.current = false; }; }); return isMounted; } const App = () => { const [state, setState] = useState(''); // 👇️ use hook const isMountedRef = useIsMounted(); useEffect(() => { async function fetchData() { const result = await Promise.resolve(['hello', 'world']); // 👇️ only update state if component is mounted if (isMountedRef.current) { setState(result); } } fetchData(); }, [isMountedRef]); return ( <div> <h2>State: {JSON.stringify(state)}</h2> </div> ); }; export default App;

The useRef() hook can be passed an initial value as an argument. The hook returns a mutable ref object whose .current property is initialized to the passed argument.

We track whether the component is mounted in our useIsMounted hook, just like we did directly in the component's useEffect hook.

Notice that in our fetchData function, we have to check for the value of isMountedRef.current because the current property on the ref is the ref's actual value.

Use the search field on my Home Page to filter through my more than 1,000 articles.