卸载组件时对setState发出警告

时间:2017-10-08 20:21:30

标签: javascript reactjs ecmascript-6 components

当我执行以下代码时(请参阅下面的代码段),我收到警告:

  

警告:setState(...):只能更新已安装或安装的组件。这通常意味着您在已卸载的组件上调用了setState()。这是一个无操作。请检查Blinker组件的代码。

我的Mounter类下的componentWillUnmount()方法中是否存在错误?谢谢!

class Blinker extends React.Component {
   constructor(props) {
    super();
    this.state = {
      appear: true
    }
    this.blinker = this.blinker.bind(this);
  }

  blinker()  {
    this.setState({appear: !this.state.appear });
  }

  componentDidMount() {
    setInterval(this.blinker, 300)
  }

  render() {
    return (
      <div>
        { (this.state.appear) && "xxx" }
      </div>
    );
  }
}

class Mounter extends React.Component {
  constructor(props) {
    super();
    this.state = {
      render: true
    };
    this.interval = null;
  }

  componentDidMount() {
    this.interval = setTimeout( () =>
      this.rendering(), 1500
    );
  }

  componentWillUnmount() {
    clearInterval(this.interval);
  }

  rendering() {
    this.setState({ render: !this.state.render });
  }

  render() {
    return (
      <div>
        <h1>
          { this.state.render && <Blinker /> }
        </h1>
      </div>
    );
  }   
}



ReactDOM.render(<Mounter />, app);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id="app"></div>

2 个答案:

答案 0 :(得分:1)

定时器方法可能很棘手,因为它们可能在componentWillUnmount触发之前触发,但状态设置可能在组件卸载后发生,因为setState是异步的。要处理此问题,您可以使用react-timer-mixin

  

反应定时器-MIXIN

     

使用裸setTimeout,setInterval,setImmediate和   requestAnimationFrame调用非常危险,因为如果你忘了   在卸载组件之前取消请求,您冒着风险   回调抛出异常。

     

如果您包含TimerMixin,那么您可以将呼叫替换为   setTimeout(fn, 500) this.setTimeout(fn, 500) {仅限前置   this。)一切都将为您妥善清理。

答案 1 :(得分:1)

清除this.interval并在设置状态前进行检查。这样可以防止在卸载组件时设置状态。

componentWillUnmount() {
  clearInterval(this.interval);
  this.interval = null; // clear
}

rendering() {
  // this.interval will be null when unmounting so avoid setting state:
  if (this.interval) {
    this.setState({
      render: !this.state.render
    });
  }
}