React JSX for loop仅显示最后一个值

时间:2019-01-13 20:09:53

标签: javascript reactjs

我在这里看到了类似的问题,但到目前为止这些问题没有帮助。

我有一个具有数组状态的组件:

eventData: []

一些逻辑监视事件并将对象推送到状态数组:

eventData.unshift(result.args);

this.setState({ eventData });;

unshift()用于将新元素推到数组顶部。

我要实现的是渲染状态数组的内容。我编写了一个条件,该条件检查某个状态,并根据该状态决定要输出的内容。

let allRecords;

if (this.state.allRecords) {
  for (let i = 0; i < this.state.eventData.length; i++) {
    (i => {
      allRecords = (
        <div className="event-result-table-container">
          <div className="result-cell">
            {this.state.eventData[i].paramOne}
          </div>
          <div className="result-cell">
            {() => {
              if (this.state.eventData[i].paramTwo) {
                <span>Win</span>;
              } else {
                <span>Loose</span>;
              }
            }}
          </div>
          <div className="result-cell">
            {this.state.eventData[i].paramThree.c[0]}
          </div>
          <div className="result-cell">
            {this.state.eventData[i].paramFour.c[0]}
          </div>
          <div className="result-cell">
            {this.state.eventData[i].paramFive.c[0] / 10000}
          </div>
          <div className="result-cell-last">
            {this.state.eventData[i].paramSix.c[0]}
          </div>
        </div>
      );
    }).call(this, i);
  }
} else if (!this.state.allRecords) {
  for (let i = 0; i < this.state.eventData.length; i++) {
    if (this.state.account === this.state.eventData[i].paramOne) {
      (i => {
        allRecords = (
          <div className="event-result-table-container">
            <div className="result-cell">
              {this.state.eventData[i].paramOne}
            </div>
            <div className="result-cell">
              {() => {
                if (this.state.eventData[i].paramTwo) {
                  <span>Win</span>;
                } else {
                  <span>Loose</span>;
                }
              }}
            </div>
            <div className="result-cell">
              {this.state.eventData[i].paramThree.c[0]}
            </div>
            <div className="result-cell">
              {this.state.eventData[i].paramFour.c[0]}
            </div>
            <div className="result-cell">
              {this.state.eventData[i].paramFive.c[0] / 10000}
            </div>
            <div className="result-cell-last">
              {this.state.eventData[i].paramSix.c[0]}
            </div>
          </div>
        );
      }).call(this, i);
    }
  }
}

这段代码存在的问题:

  1. 代码始终呈现eventData状态对象的最后一个值。
  2. 我想将渲染的元素限制为始终显示不超过20个对象(状态数组的最后20条记录)。
  3. paramTwo 是布尔值,根据其值,我希望看到 Win Loose ,但是该字段为空(我通过bool获得console.log的值,所以我知道该值在那里)

这甚至是实现所需的最有效方法吗?我也在考虑通过元素进行映射,但是决定坚持使用for循环。

感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

几件事:

首先,正如上面的评论所指出的,不使用setState来更改状态与React的工作方式背道而驰,解决此问题的最简单解决方案是执行以下操作:

this.setState(prevState => ({ 
    eventData: [...prevState.eventData, result.args]
}));

此处的代码有问题。箭头函数从未被调用过吗?

{() => {
        if (this.state.eventData[i].paramTwo) {
            <span>Win</span>;
        } else {
            <span>Loose</span>;
        }
    }
}

此功能可以简化为以下功能(应用下面的代码中的解构之后):

<span>{paramTwo ? 'Win' : 'Lose'}</span>

接下来,通过映射删除函数中的重复项。通过在适当的位置设置条件并使用三元数,可以将代码简化为以下内容,并将其直接包含在render函数的JSX部分中:

render(){
    return(
        <div> //Could also be a fragment or anything
            {this.state.allRecords || this.state.account === this.state.eventData[i].paramOne && 
                this.state.eventData.map(({ paramOne, paramTwo, paramThree, paramFour, paramFive, paramSix }, i) =>
                    <div className="event-result-table-container" key={i}> //Don't forget the key like I just did before editing
                        <div className="result-cell">
                            {paramOne}
                        </div>
                        <div className="result-cell">
                            <span>{paramTwo ? 'Win' : 'Lose'}</span>
                        </div>
                        <div className="result-cell">
                            {paramThree.c[0]}
                        </div>
                        <div className="result-cell">
                            {paramFour.c[0]}
                        </div>
                        <div className="result-cell">
                            {paramFive.c[0] / 10000}
                        </div>
                        <div className="result-cell-last">
                            {paramSix.c[0]}
                        </div>
                    </div>
                )
            }
        </div>
    )
}

最后,仅获取数组的前20个元素,请使用slice

this.state.eventData.slice(0, 20).map(/*  CODE ABOVE */)

编辑:

对不起,在理解您在渲染中使用的条件时,我犯了一个错误,这是代码开头的固定版本:

{this.state.allRecords && 
    this.state.eventData.filter(data => this.state.account === data.paramOne).slice(0, 20).map(/* CODE ABOVE */)

在这里,我们使用filter仅使用符合给定条件的数组元素。


编辑2:

我刚刚犯了另一个错误,希望是最后一个错误。这应该具有正确的逻辑:

this.state.eventData.filter(data => this.state.allRecords || this.state.account === data.paramOne).slice(0, 20).map(/* CODE ABOVE */)

如果定义了this.state.allRecords,它将接受所有内容;否则,它将检查您的状况。

答案 1 :(得分:0)

我清理了一下并重构了您的代码。我为重复逻辑编写了一个通用函数,然后将循环对象传递给通用函数以进行渲染。

使用Map代替forloops。您确实需要检查此this.state.account === this.state.eventObj.paramOne语句。这可能是您在屏幕上仅看到一项的原因。

请共享一些伪数据和unshift部分后面的逻辑(切勿直接在状态对象上进行操作),我们将对其进行修复。

getRecord = (eventObj) => (
  <React.Fragment>
    <div className="result-cell">
      {eventObj.paramOne}
    </div>
    <div className="result-cell">
      {eventObj.paramTwo ? <span>Win</span> : <span>Loose</span>}
    </div>
    <div className="result-cell">
      {eventObj.paramThree.c[0]}
    </div>
    <div className="result-cell">
      {eventObj.paramFour.c[0]}
    </div>
    <div className="result-cell">
      {eventObj.paramFive.c[0] / 10000}
    </div>
    <div className="result-cell-last">
      {eventObj.paramSix.c[0]}
    </div>
  </React.Fragment>
)


render() {
  let allRecords;

  if (this.state.allRecords) {
    allRecords = <div>{this.state.eventData.map(eventObj => this.getRecord(eventObj)}</div>;
  } else if (!this.state.allRecords) {
    allRecords = <div>{this.state.eventData.map(eventObj => {
      if (this.state.account === this.state.eventObj.paramOne) {
        return this.getRecord(eventObj);
      }
      return null;
    })}</div>;
  }
  return (<div className="event-result-table-container">{allRecords}</div>);
}