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');
}
错误:
警告:setState(...):只能更新已安装或已安装 零件。这通常意味着您在已卸载时调用了setState() 零件。这是一个无操作。请检查未定义的代码 成分
我在componentWillUnmount
中删除了'EventListener'已结束',但它无效。因为我在this.setState({'time': remainTimeInfo});
中添加了componentDidMount
。
答案 0 :(得分:96)
我通过为组件分配 ref 然后在设置状态之前检查ref是否存在来解决这个问题:
myMethod(){
if (this.refs.myRef)
this.setState({myVar: true});
}
render() {
return (
<div ref="myRef">
{this.state.myVar}
</div>
);
}
答案 1 :(得分:23)
removeEventListener
与addEventListener
具有相同的签名。删除侦听器的所有参数必须完全相同。
var onEnded = () => {};
audioNode.addEventListener('ended', onEnded, false);
this.cleanup = () => {
audioNode.removeEventListener('ended', onEnded, false);
}
并在componentWillUnmount中调用this.cleanup()
。
答案 2 :(得分:4)
我遇到了这个问题,因为我在构造函数中使用了setState
而不是state
。
示例强>
更改以下错误代码
constructor(props) {
super(props);
this.setState({
key: ''
});
}
到
constructor(props) {
super(props);
this.state = {
key: ''
};
}
答案 3 :(得分:3)
修改:isMounted
已弃用,可能会在更高版本的React中删除。请参阅this和此isMounted is an Antipattern。
如警告所述,您在 已挂载的组件上调用this.setState
但从那时起已卸载。
为了确保您的代码安全,您可以将其包装在
中if (this.isMounted()) {
this.setState({'time': remainTimeInfo});
}
确保组件仍然安装。
答案 4 :(得分:3)
因为我更新了最新的反应版本,所以我遇到了同样的问题。解决方法如下。
我的代码是
async componentDidMount() {
const { default: Component } = await importComponent();
Nprogress.done();
this.setState({
component: <Component {...this.props} />
});
}
已更改为
componentWillUnmount() {
this.mounted = false;
}
async componentDidMount() {
this.mounted = true;
const { default: Component } = await importComponent();
if (this.mounted) {
this.setState({
component: <Component {...this.props} />
});
}
}
答案 5 :(得分:2)
之前我遇到过这个问题,并根据React官方网页isMounted is an Antipattern解决了这个问题。
在isMounted
中将属性componentDidMount
标记设置为true,并在componentWillUnmount
中将其切换为false。当您在回调中setState()
时,请先检查isMounted
!它对我有用。
state = {
isMounted: false
}
componentDidMount() {
this.setState({isMounted: true})
}
componentWillUnmount(){
this.setState({isMounted: false})
}
回调:
if (this.state.isMounted) {
this.setState({'time': remainTimeInfo});}
答案 6 :(得分:1)
这个帖子中的很多答案都得到了使用refs的意义,但我认为一个完整的例子会很好。由于您通过使用事件侦听器并退出React上下文来操作实际DOM节点,因此应将ref视为标准解决方案。这是一个完整的例子:
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)
}
}
答案 7 :(得分:1)
addEventListener和removeEventListener,Callback不能是Anonymous内部类,并且它们应该具有相同的参数
答案 8 :(得分:0)
当我想在Ajax请求的成功/失败回调中显示弹出窗口(引导模式)时,我收到了此警告。另外setState没有工作,我的弹出模式没有显示。
以下是我的情况 -
<Component /> (Containing my Ajax function)
<ChildComponent />
<GrandChildComponent /> (Containing my PopupModal, onSuccess callback)
我从孙子组件调用组件的ajax函数,传递一个onSuccess Callback(在孙子组件中定义),它正在设置状态以显示弹出模式。
我把它改为 -
<Component /> (Containing my Ajax function, PopupModal)
<ChildComponent />
<GrandChildComponent />
相反,我调用setState(onSuccess Callback)来显示组件(ajax回调)本身的弹出模式并解决问题。
在第二种情况下:组件被渲染两次(我在html中包含了两次bundle.js)。
答案 9 :(得分:0)
在audioNode.addEventListener
的回调中使用命名方法代替匿名函数应消除主题警告:
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});
}
}
是的,反正还是需要命名方法,因为removeEventListener
不能与匿名回调一起使用,如上所述。
答案 10 :(得分:0)
componentWillUnmount
中的所有异步操作setState
时,检查组件已经卸载,答案 11 :(得分:0)
我遇到了这个问题,但上述解决方案不起作用。结果我不小心忘记将“this”绑定到我的一个类方法。
那是一个多么漫长的夜晚:(
错误代码
class App extends React.Component{
constructor(props,context){
super(props,context)
this.state={
x:true,
y:false
}
this.methodY=this.methodY.bind(this)
this.methodX=this.methodX(this) //error
}
}
正确的代码
class App extends React.Component{
constructor(props,context){
super(props,context)
this.state={
x:true,
y:false
}
this.methodY=this.methodY.bind(this)
this.methodX=this.methodX.bind(this)
}
}