React setState 在调用时渲染组件两次

Posted

技术标签:

【中文标题】React setState 在调用时渲染组件两次【英文标题】:React setState renders component twice when called 【发布时间】: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>
    )
  

【问题讨论】:

【参考方案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,我已经编辑了我的答案,以展示你可以这样做的方式。

以上是关于React setState 在调用时渲染组件两次的主要内容,如果未能解决你的问题,请参考以下文章

在 React 组件中多次使用 this.setState 会发生啥?

即使在调用 setState 之后,React.js 子状态也不会重新渲染?

setState源码分析

React setstate 只能更新挂载或挂载的组件——在重新渲染时

在 React 中,为啥子组件的渲染函数会被调用两次?

React Native this.setState() 仅在再次与组件交互后重新渲染