setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op

Reactjs

Reactjs Problem Overview


componentDidMount(prevProps, prevState, prevContext) {
    let [audioNode, songLen] = [this.refs.audio, List.length-1];

    audioNode.addEventListener('ended', () => {
        this._endedPlay(songLen, () => {
            this._currSong(this.state.songIndex);
            this._Play(audioNode);
        });
    });

    audioNode.addEventListener('timeupdate', () => {
        let [remainTime, remainTimeMin, remainTimeSec, remainTimeInfo] = [];

        if(!isNaN(audioNode.duration)) {
            remainTime = audioNode.duration - audioNode.currentTime;
            remainTimeMin = parseInt(remainTime/60);  // 剩余分
            remainTimeSec = parseInt(remainTime%60);  // 剩余秒

            if(remainTimeSec < 10) {
                remainTimeSec = '0'+remainTimeSec;
            }
            remainTimeInfo = remainTimeMin + ':' + remainTimeSec;
            this.setState({'time': remainTimeInfo});
        }
    });
}

componentWillUnmount () {
    let audio = this.refs.audio;
    audio.removeEventListener('timeupdate');
    audio.removeEventListener('ended');
}

Error:

> Warning: setState(...): Can only update a mounted or mounting > component. This usually means you called setState() on an unmounted > component. This is a no-op. Please check the code for the undefined > component.

I removeEventListener 'ended' in componentWillUnmount, but it is not working. because I add this.setState({'time': remainTimeInfo}); in componentDidMount.

Reactjs Solutions


Solution 1 - Reactjs

I solved this by assigning a ref to the component and then checking if the ref exists before setting the state:

myMethod(){
  if (this.refs.myRef) 
   this.setState({myVar: true});
}

render() {
  return (
    <div ref="myRef">
      {this.state.myVar}
    </div>
  );
}

And lately, since I am using mostly functional components, I am using this pattern:

const Component = () => {
  const ref = React.useRef(null);
  const [count, setCount] = React.useState(0);

  const increment = () => {
    setTimeout(() => { // usually fetching API data here
      if (ref.current !== null) {
        setCount((count) => count + 1);
      }
    }, 100);
  };

  return (
    <button onClick={increment} ref={ref}>
      Async Increment {count}
    </button>
  );
};

Solution 2 - Reactjs

removeEventListener has the same signature as addEventListener. All of the arguments must be exactly the same for it to remove the listener.

var onEnded = () => {};
audioNode.addEventListener('ended', onEnded, false);

this.cleanup = () => {
  audioNode.removeEventListener('ended', onEnded, false);
}

And in componentWillUnmount call this.cleanup().

Solution 3 - Reactjs

I encountered this issue because I used setState instead of state in the constructor.

EXAMPLE

Change the following incorrect code

constructor(props) {
  super(props);
  this.setState({
    key: ''
  });
}

to

constructor(props) {
  super(props);
  this.state = {
    key: ''
  }; 
}

Solution 4 - Reactjs

Edit: isMounted is deprecated and will probably be removed in later versions of React. See this and this, isMounted is an Antipattern.


As the warning states, you are calling this.setState on an a component that was mounted but since then has been unmounted.

To make sure your code is safe, you can wrap it in

if (this.isMounted()) {
	this.setState({'time': remainTimeInfo});
}

to ensure that the component is still mounted.

Solution 5 - Reactjs

I have faced same problem since I have updated the latest react version. Solved like below.

My code was

async componentDidMount() {
  const { default: Component } = await importComponent();
  Nprogress.done();
  this.setState({
    component: <Component {...this.props} />
  });
}

Changed to

componentWillUnmount() {
  this.mounted = false;
}
async componentDidMount() {
  this.mounted = true;
  const { default: Component } = await importComponent();
  if (this.mounted) {
    this.setState({
      component: <Component {...this.props} />
    });
  }
}

Solution 6 - Reactjs

I had this problem before, and solved it according to React official page isMounted is an Antipattern.

Set a property isMounted flag to be true in componentDidMount , and toggle it false in componentWillUnmount. When you setState() in your callbacks, check isMounted first! It works for me.

state = {
    isMounted: false
  }
  componentDidMount() {
      this.setState({isMounted: true})
  }
  componentWillUnmount(){
      this.setState({isMounted: false})
  }

callback:

if (this.state.isMounted) {
 this.setState({'time': remainTimeInfo});}

Solution 7 - Reactjs

A lot of the answers in this thread get the point of using refs, but I think a complete example would be good. Since you're operating on an actual DOM node by using the event listener and stepping out of the React context, a ref should be considered the standard solution. Here's a complete example:

class someComponent extends Component {
  constructor(props) {
    super(props)
    this.node = null
  }
  render() {
    return (
      <div ref={node => { this.node = node }}>Content</div>
    )
  }
  handleEvent(event) {
    if (this.node) {
      this.setState({...})
    }
  }
  componentDidMount() {
    //as soon as render completes, the node will be registered.
    const handleEvent = this.handleEvent.bind(this)
    this.node.addEventListener('click', handleEvent)
  }
  componentWillUnmount() {
    const handleEvent = this.handleEvent.bind(this)
    this.node.removeEventListener('click', handleEvent)
  }
}

Solution 8 - Reactjs

addEventListener and removeEventListener,the Callback must not be Anonymous inner class,and they should have the same params

Solution 9 - Reactjs

I was getting this warning when I wanted to show a popup (bootstrap modal) on success/failure callback of Ajax request. Additionally setState was not working and my popup modal was not being shown.

Below was my situation-

<Component /> (Containing my Ajax function)
    <ChildComponent />
        <GrandChildComponent /> (Containing my PopupModal, onSuccess callback)

I was calling ajax function of component from grandchild component passing a onSuccess Callback (defined in grandchild component) which was setting state to show popup modal.

I changed it to -

<Component /> (Containing my Ajax function, PopupModal)
    <ChildComponent />
        <GrandChildComponent /> 

Instead I called setState (onSuccess Callback) to show popup modal in component (ajax callback) itself and problem solved.

In 2nd case: component was being rendered twice (I had included bundle.js two times in html).

Solution 10 - Reactjs

Having named method in place of the anonymous function in audioNode.addEventListener 's callback should eliminate the subject warning:

	componentDidMount(prevProps, prevState, prevContext) {
	let [audioNode, songLen] = [this.refs.audio, List.length-1];

	audioNode.addEventListener('ended', () => {
		this._endedPlay(songLen, () => {
			this._currSong(this.state.songIndex);
			this._Play(audioNode);
		});
	});

	audioNode.addEventListener('timeupdate', this.callbackMethod );
}

callBackMethod = () => {
	let [remainTime, remainTimeMin, remainTimeSec, remainTimeInfo] = [];

	if(!isNaN(audioNode.duration)) {
		remainTime = audioNode.duration - audioNode.currentTime;
		remainTimeMin = parseInt(remainTime/60);  // 剩余分
		remainTimeSec = parseInt(remainTime%60);  // 剩余秒

		if(remainTimeSec < 10) {
			remainTimeSec = '0'+remainTimeSec;
		}
		remainTimeInfo = remainTimeMin + ':' + remainTimeSec;
		this.setState({'time': remainTimeInfo});
	}
}

And yes, named method is needed anyways because removeEventListener won't work with anonymous callbacks, as mentioned above several times.

Solution 11 - Reactjs

  1. Cancel all async operation in componentWillUnmount
  2. Check component is already unmounted when async call setState,
    since isMounted flag is deprecated

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionuseLess liangView Question on Stackoverflow
Solution 1 - ReactjsTudor MorarView Answer on Stackoverflow
Solution 2 - ReactjsBrigandView Answer on Stackoverflow
Solution 3 - ReactjsSeareneView Answer on Stackoverflow
Solution 4 - ReactjsDaniel BView Answer on Stackoverflow
Solution 5 - ReactjsJaison JamesView Answer on Stackoverflow
Solution 6 - Reactjsuser6042449View Answer on Stackoverflow
Solution 7 - ReactjsZachary SkalkoView Answer on Stackoverflow
Solution 8 - ReactjsMingoView Answer on Stackoverflow
Solution 9 - ReactjsVarun KumarView Answer on Stackoverflow
Solution 10 - ReactjsVasiliyView Answer on Stackoverflow
Solution 11 - ReactjsShawn WangView Answer on Stackoverflow