Javascript SetState和PreviousState的定时问题

Javascript SetState和PreviousState的定时问题,javascript,reactjs,Javascript,Reactjs,我是一个新的反应和有一个问题可能与线程 我有一个父类,它创建了一系列按钮(通过数组映射) 父类将按钮添加到计时器上的数组中。而子类有一个onclick属性,该属性调用父方法来移除按钮 “删除”按钮似乎并不总是删除右侧按钮。我正在使用setState和previousState功能。我想知道我做错了什么 我将显示父类和子类。我试图不包括所有的导入类和其他类来简化这个问题,很抱歉代码仍然很长 家长: class PanelDiv extends Component { constructor(p

我是一个新的反应和有一个问题可能与线程

我有一个父类,它创建了一系列按钮(通过数组映射)

父类将按钮添加到计时器上的数组中。而子类有一个onclick属性,该属性调用父方法来移除按钮

“删除”按钮似乎并不总是删除右侧按钮。我正在使用setState和previousState功能。我想知道我做错了什么

我将显示父类和子类。我试图不包括所有的导入类和其他类来简化这个问题,很抱歉代码仍然很长

家长:

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) => {
      var foundIndex = previousState.items.findIndex(function(element) {
        console.log(clientId);
        return element.toString() === clientId.substring(2);
      });

      previousState.items.splice(foundIndex, 1);
      return { items: previousState.items };
    });
  }

  addChild() {
    this.setState((previousState, currentProps) => {
      return {
        items: previousState.items.concat([
          previousState.items[previousState.items.length - 1] + 1
        ])
      };
    });
  }
}
class PanelDiv扩展组件{
建造师(道具){
超级(道具);
this.state={items:[0]};
this.addChild=this.addChild.bind(this);
this.buttonClickHandler=this.buttonClickHandler.bind(this);
}
render(){
返回(
this.PanelLoaded()}
风格={{
宽度:“100%”,
高度:“100%”,
backgroundImage:“url”(“+backgroundImage+”),
背景尺寸:“封面”
}}
>
{this.state.items.map(item=>(
))}
);
}
componentDidMount(){
setInterval(this.addChild、Settings.COMPONENT\u ADD\u INTERVAL);
}
按钮ClickHandler(客户端ID){
this.setState((以前的状态,currentProps)=>{
var foundIndex=previousState.items.findIndex(函数(元素){
console.log(clientId);
返回元素.toString()==clientId.substring(2);
});
previousState.items.splice(foundIndex,1);
返回{items:previousState.items};
});
}
addChild(){
this.setState((以前的状态,currentProps)=>{
返回{
项目:previousState.items.concat([
previousState.items[previousState.items.length-1]+1
])
};
});
}
}
儿童:

class NumberButton extends Component {
  constructor(props) {
    super(props);
    var varLeft = (0 + Math.random() * (100 - 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.buttonClicked = this.buttonClicked.bind(this);

    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();
  }

  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);
  }
}
class NumberButton扩展组件{
建造师(道具){
超级(道具);
var varLeft=(0+Math.random()*(100-0)).toString()+“%”;
var超时值=
Settings.BUTTON\u SPEED\u MIN+
Math.random()*(Settings.BUTTON\u SPEED\u MAX-Settings.BUTTON\u SPEED\u MIN);
var numberValue=Math.round(Math.random()*Settings.MAX_NUMBER);
this.buttonClicked=this.buttonClicked.bind(this);
此.state={
clientId:props.id,
wavePath:Waves[numberValue],
左:左,
排名:0,
柜台:“你好”,
timeoutValue:timeoutValue,
numberValue:numberValue
};
}
updateCount(){
this.setState((prevState,props)=>{
返回{top:prevState.top+1};
});
setTimeout(()=>this.updateCount()、this.state.timeoutValue);
}
componentDidMount(){
this.updateCount();
}
render(){
返回(
this.buttonClicked()}
风格={{
颜色:“白色”,
fontSize:Settings.BUTTON\u字体大小,
fontFamily:“Verdana”,
边界:“无”,
背景色:“透明”,
背景尺寸:“封面”,
背景图片:“url(“+CoconutImage+”),
位置:“绝对”,
左:这个州,左,
top:this.state.top,
宽度:设置。按钮的宽度和高度,
高度:设置。按钮\u宽度\u和\u高度
}}
>
{this.state.numberValue}
);
}
按钮点击(){
var audio=新音频(this.state.wavePath);
音频播放();
this.props.parentClickHandler(this.state.clientId);
}
}

您不应该在状态中改变对象。您应该根据以前的状态返回新对象


按钮ClickHandler(客户端ID){
this.setState((以前的状态,currentProps)=>({
items:previousState.items.filter(元素=>(
element.toString()!==clientId.substring(2))
)
}));

}
该问题是由于值为NaN的重复密钥问题引起的

这就是解决办法:

  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])};
    });
  }

它比另一个更有效,但有时我会发现问题是多个函数被删除了,就像另一个函数一样…所以类似的并发问题我解决了…我有时有一个带有nan的键…当列表为空时