(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 –
- In class based components
componentWillUnmount()
is called just before the unmounting of component. - 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
- Define a variable
var isMountedVal = 1
in constructor. - Declare a function to do all the state updates in the component. Before calling
setState
check if value ofisMountedVal
is 1. - Set
isMountedVal = 0
incomponentWillUnmount
.
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> ); }