Can’t perform a react state update on an unmounted component – Code

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

(Jump to Solution | Code | Demo) There are number of situations when you get the warning, “Can’t perform a react state update on an unmounted component“. One thing is certain that somewhere in your code you are using setState or useState hook function even after unmounting the component.

The issue is not, why we are getting this warning, else, we need to know how to deal with it properly. But, one reason for the warning is to update state inside setTimeout or setInterval because the function gets called asynchronously after a given time period. If we do not clear timeout or interval during unmounting of component then function will run and there will be no component available to update.

Another reason for getting this warning is to use asynchronous api calls without unsubscribing them during unmount.

Solution

The solution of our problem is to prevent updating state after a component is unmounted.

But how we will know if a component is unmounted?

React provides two solutions for these –

  1. In class based components componentWillUnmount() is called just before the unmounting of component.
  2. In functional components we return an anonymous function in useEffect() hook. This anonymous function gets called before a new render cycle. So we do all unmounting stuff there.

You may also like –

Procedure to prevent warning

  1. Define a variable var isMountedVal = 1 in constructor.
  2. Declare a function to do all the state updates in the component. Before calling setState check if value of isMountedVal is 1.
  3. Set isMountedVal = 0 in componentWillUnmount.

Code Example

Class based component –

import React from 'react'
export default class App extends React.Component{
	constructor(props){
		super(props);
		this.isMountedVal = 0;
		this.state = {count: 1};
	}
	
	componentDidMount(){
		this.isMountedVal = 1;
	}
	
	componentWillUnmount(){
		this.isMountedVal = 0;
	}
	
	updateState = (stateObj) => {
		if(this.isMountedVal){
			this.setState(stateObj);
		}
	}
	
	render(){
		return(
			<div>
				<p>Count: {this.state.count}</p>
				<p><button onClick={() => this.updateState({count: this.state.count + 1})}>Increase Count by 1</button></p>
			</div>
		);
	}
}

Functional Component –

import React, {useState, useEffect, useRef} from 'react'
export default App(){
	const [count, setCount] = useState(1);
	const isMountedVal = useRef(1);
	
	useEffect(() => {
		isMountedVal.current = 1;
		
		return () => {isMountedVal.current = 0;};
	})
	
	const updateState = (callback) => {
		if(isMountedVal.current){
			callback();
		}
	}
	
	return(
		<div>
			<p>Count: {count}</p>
			<p><button onClick={() => updateState(() => setCount(count + 1))}>Increase Count by 1</button></p>
		</div>
	);
}

    Tweet this to help others

Live Demo

Open Live Demo