【问题标题】:React setState renders component twice when calledReact setState 在调用时渲染组件两次
【发布时间】:2017-07-23 21:56:04
【问题描述】:

我正在尝试构建一个连接 4 游戏,它有一个由 7 个列组件组成的棋盘组件,所有组件都包含 6 个空间组件。每列上方都有一个放置按钮,用于将片段放入列中。为了在“红色”和“黑色”玩家之间交替,我创建了一个状态“redOrBlue”,它返回一个布尔值。

简而言之,当单击 Drop 按钮时,我想切换“redOrBlue”的值以跟踪轮到谁了。我已将 onClick 函数设置为 setState({redOrBlue: !this.state.redOrBlue)},但是,调用此函数将导致 react 在单击按钮的列的正下方呈现一个额外的列。我知道 setState 会自动重新渲染 DOM,但我怎样才能避免它渲染组件的副本?感谢您的帮助!

class Column extends Component{
  constructor(){
    super();
    this.state = {
      myArray: [],
      buttonArray: [],
      buttonNumber: null,
      newArray: [],
      redOrBlue: true
    }
  }
  makeRow(){
    var component = <Space className="space"/>
    for(var i = 0; i < 6; i++){
      this.state.myArray.push(component);
    }
  }

  handleClick(){
    var num = this.props.colNumber;
    var array = this.props.boardArray[num];
    var boolean = false;
    var color;
    if(this.state.redOrBlue === true){
      color = "red"
    }else{
      color = "black"
    }
    for(var i = 5; i > -1; i--){
      if(boolean === false){
        if(array[i] === null){
          array[i] = color;
          boolean = true;
        }
      }
    }
    this.setState({redOrBlue: !this.state.redOrBlue})
    console.log(array)
  }

  render(){
    {this.makeRow()}
    return(
      <div className="column">
        <DropButton onClick={() => this.handleClick()} id={'button-' + this.props.colNumber} buttonNumber={this.props.colNumber} className={this.props.className}/>
        {this.state.myArray.map(function(component, key){
          return component
        })}
      </div>
    )
  }
}

【问题讨论】:

    标签: javascript reactjs components


    【解决方案1】:

    您需要在代码中更改许多内容:

    *首先从不ui items存储在状态变量中,state变量应该只包含数据和值。

    *永远不要通过this.state.a = '' or this.state.a.push({})state 变量进行任何更改,始终将state 值视为不可变,并且仅使用setState 来更改值。

    *总是在render 中调用函数,如果你想创建dynamically 的东西,它将直接创建ui part

    从 render 中调用makeRow 方法,它会直接返回 ui 而不将其存储在 state 变量中,如下所示:

    makeRow(){
        var component = [];
        for(var i = 0; i < 6; i++){
          component.push(<Space key={i} className="space"/>);
        }
        return component;
     }
    
    render(){
        return(
            <div className="column">
                <DropButton onClick={() => this.handleClick()} id={'button-' + this.props.colNumber}
                    buttonNumber={this.props.colNumber} className={this.props.className}/>
                {this.makerow()}
            </div>
        )
    }
    

    【讨论】:

      【解决方案2】:

      从您的渲染函数中删除 {this.makeRow()}。您所做的只是在每次组件呈现时以一种相当不洁净的方法向状态添加另一行。试试这样的:

        constructor(){
          super();
          this.state = {
            myArray: [],
            buttonArray: [],
            buttonNumber: null,
            newArray: [],
            redOrBlue: true
          }
          this.makeRow();
        }
        makeRow(){
          var tempArray = [];
          var component = <Space className="space"/>
          for(var i = 0; i < 6; i++){
            tempArray.push(component);
          }
          this.setState({ myArray: tempArray }};
        }
      

      【讨论】:

      • 好的,那么当页面加载时我在哪里/如何调用该函数?
      • 您有几个选择。从构造函数中调用该函数可能是最简单的方法。
      • @IanSpringer,我已经编辑了我的答案,以展示你可以这样做的方式。
      猜你喜欢
      • 1970-01-01
      • 2018-04-04
      • 2019-05-26
      • 1970-01-01
      • 2017-12-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-27
      相关资源
      最近更新 更多