React单击以卸载组件消息

时间:2018-09-25 01:21:24

标签: javascript reactjs

在卸载组件时获取此消息:

  

警告:无法在已卸载的设备上调用setState(或forceUpdate)   零件。这是空操作,但表示您的内存泄漏   应用。要修复,请取消所有订阅和异步任务   在componentWillUnmount方法中。       在NumberButton中(在App.js:37)

我有一个父母,有一个带有按钮列表的数组。每个按钮都有一个onclick来调用父级,这将从列表中删除单击的按钮。

问题在于该函数的用途是单击以实质上破坏其自身。该方法的完成方式不需要显式绑定,而无需显式绑定就不需要解除绑定,因此我认为组件中不会存在内存泄漏。

请告知我为什么会收到此消息,我可以做什么以及如果它是假阳性消息。

父类:

class PanelDiv extends Component
{
  constructor(props) {
    super(props);
    this.state = {items: [0]};
    this.addChild = this.addChild.bind(this);
    this.buttonClickHandler = this.buttonClickHandler.bind(this);
  }

  render()
  {
    return (<div id="DivBackground" onLoad={() => this.PanelLoaded()} style={{width: '100%', height: '100%', backgroundImage: "url(" + BackgroundImage + ")", backgroundSize: "cover"}}>
      {
          this.state.items.map((item) => (
            <NumberButton key={"Nb" + item.toString()} parentClickHandler={this.buttonClickHandler} id={"Nb" + item.toString()} />
          ))
      }
    </div>);
  }

  componentDidMount()
  {
    setInterval(this.addChild, Settings.COMPONENT_ADD_INTERVAL);
  }

  buttonClickHandler(clientId) {

    this.setState((previousState, currentProps) => ({
      items: previousState.items.filter(element => {

        return element.toString() !== clientId.substring(2)

      }
        //console.log("Matching Element: ")
      )
    }));
  }

  componentWillUnmount() {

  }

  addChild() 
  {

    this.setState((previousState, currentProps) => {

        if (previousState.items.length == 0)
          return {items:[0]};
        else
          return {items: previousState.items.concat([previousState.items[previousState.items.length-1]+1])};
    });
  }
}

儿童班:

class NumberButton extends Component
{

  constructor(props) {
    super(props);
    var varLeft = (0 + (Math.random() * (90-0))).toString() + '%';
    var timeoutValue = Settings.BUTTON_SPEED_MIN + (Math.random() * (Settings.BUTTON_SPEED_MAX-Settings.BUTTON_SPEED_MIN));
    var numberValue = Math.round(Math.random() * (Settings.MAX_NUMBER));


    this.state = { clientId: props.id, wavePath: Waves[numberValue], left: varLeft, top: 0, counter: "Hello", timeoutValue: timeoutValue, numberValue: numberValue };
  }


  updateCount() {

    this.setState((prevState, props) => {
      return { top: prevState.top + 1 }
    });
    setTimeout(()=> this.updateCount(), this.state.timeoutValue)

  }

  componentDidMount()
  {
    this.updateCount();
    //this.buttonClicked = this.buttonClicked.bind(this);
  }

  componentWillUnmount() {

  }

  render()
  {
    return (
      <button id={this.state.clientId} onClick={() => this.buttonClicked()} style={{color: "white", fontSize: Settings.BUTTON_FONT_SIZE, fontFamily: "Verdana", border: "none", backgroundColor: "Transparent", backgroundSize: "cover", backgroundImage: "url(" + CoconutImage + ")", position: "absolute", left: this.state.left, top: this.state.top, width: Settings.BUTTON_WIDTH_AND_HEIGHT, height: Settings.BUTTON_WIDTH_AND_HEIGHT}}>
      {this.state.numberValue}
      </button>

    );
  }


  buttonClicked()
  {
    var audio = new Audio(this.state.wavePath);
    audio.play();
    this.props.parentClickHandler(this.state.clientId);
  }
}

This是我最初的问题,仅供参考。

2 个答案:

答案 0 :(得分:1)

每当执行setTimeout或setInterval时,都要确保在componentWillUnMount生命周期方法中清除它们。像下面这样

Dataset<Row> testDs=ds.join(functions.broadcast(dsgrouped), dsgrouped.col("tick").equalTo(ds.col("symbol"))
                .and(dsgrouped.col("Id").equalTo(ds.col("traderId")))
        .and(dsgrouped.col("maxdate").equalTo(ds.col("datetime"))));
  

componentWillUnmount旨在消除设置的间隔   挂载时更早

像子元素一样聪明

 componentDidMount() {
      this.addChildTimer = setInterval(this.addChild, Settings.COMPONENT_ADD_INTERVAL);
  }

  componentWillUnMount(){
      clearInterval(this.addChildTimer);
 }

注意:避免在setInterval内执行setState

答案 1 :(得分:0)

似乎您的代码中的问题是由计时器引起的。您的代码中有setTimeout和setInterval,即使卸载了组件,它们也将执行。因此错误现在应该更清楚了(您无法为未安装的组件设置状态)。

对代码进行以下更改。

父母阶级

componentWillMount() {
    this.intervalId = setInterval(this.addChild, Settings.COMPONENT_ADD_INTERVAL);
}

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

儿童班

this.updateCountTimout = setTimeout(()=> this.updateCount(), this.state.timeoutValue);


componentWillUnmount() {
    clearTimeout(this.updateCountTimout);
}