setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op
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
.
Solution 1:
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:
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()
.