React - 使用循环创建嵌套组件

IT技术 javascript loops reactjs inline jsx
2021-05-13 04:34:42

我对 React 有一个小问题。我无法使用 for 循环创建嵌套组件。我想要做的是创建一个表格的 9 个单元格,然后创建 3 行,每行 3 个单元格,然后将 3 行安装在一起并创建一个 9x9 的板。

假设我想得到这样的东西,但使用循环

class Board extends React.Component {     
renderSquare(i) {
    return <Square value={this.props.squares[i]} onClick={() => this.props.onClick(i)} />;
}

render(){    
    return(
        <div>
            <div className="board-row">
                {this.renderSquare(0)}
                {this.renderSquare(1)}
                {this.renderSquare(2)}
            </div>
            <div className="board-row">
                {this.renderSquare(3)}
                {this.renderSquare(4)}
                {this.renderSquare(5)}
            </div>
            <div className="board-row">
                {this.renderSquare(6)}
                {this.renderSquare(7)}
                {this.renderSquare(8)}
            </div>
        </div>
    );        
}

}

我搜索了几个小时的其他问题,我认为我的代码几乎是正确的,但它没有呈现我想要的。我只得到一个白页。

这是我的代码:

class Board extends React.Component { 

renderSquare(i) {
    return <Square value={this.props.squares[i]} onClick={() => this.props.onClick(i)} />;
}

createCells(i){
    if(i%3){return;}
    var index = this.fillN(Array(i)); //index=[0,1,2,3,4,5,6,7,8]
    var cells = [];
    index.forEach(function(i){
        cells.push(() => {
            return(
                <div>
                    {this.renderSquare(i)}
                </div>
            );
        });
    });
    return cells;
}

createRows(cells){
    var index = this.fillMod3(Array(3)); //index=[0,3,6]
    var rows = []
    index.forEach(function(i){
        rows.push(() => {
            return(
                <div>
                    {cells[i]}
                    {cells[i+1]}
                    {cells[i+2]}
                </div>
            );
        });
    });
    return rows;
}

render(){    
    var cells = this.createCells(9);
    var rows = this.createRows(cells);
    var board = [];
    var index = this.fillN(Array(1));

    index.forEach(function(row){
        board.push(() => {
            return(
                <div>{row}</div>
            );
        });
    })

    return(
        <div>
            {board[0]}
        </div>
    );        
}

我总是在屏幕上看到这样的东西:

<Board>
  <div> /*empty*/ </div>
</Board>

我想澄清一下,我确信与该组件 (Board) 交互的其余代码没有问题。

我是react的新手,如果有人可以帮助我,我会非常感激。对不起我的英语不好

EDIT1:按照marklew的例子,我应该能够做这样的事情

    render(){   
    var index1 = this.fillN(Array(3)); //index1=[0,1,2]
    var index2 = this.fillN(Array(3)); //index2=[0,1,2]

    return(
        <div>
            {index1.map((e1,i1) => {
                return(
                    <div key={i1} className="board-row">
                        {index2.map((e2, i2) => {
                            return(
                                <p key={i2+10}>
                                    {this.renderSquare(i2)}
                                </p>
                            )
                        })}
                    </div>
                )    
            })}
        </div>
    );

}

但它没有做我想要的。我只获得了一个包含 9 个单元格的列,并且这些单元格是相同的对象。我不明白为什么。(我知道这是相同的对象,因为我在创建它们时分配了一个句柄函数 onClick :

<Board 
     onClick={(i) => this.handleClick(i)} //handleClick just draws a X in the cell
     />

我同时让 X 淹没在 3 个单元格中

EDIT2:我找到了一个解决方案:

render(){   
    var index1 = this.fillMod3(Array(3));        

    return(
        <div>
            {index1.map((e,i) => {
                return(
                    <div key={i} className="board-row">
                        {this.renderSquare(e)}
                        {this.renderSquare(e+1)}
                        {this.renderSquare(e+2)}
                    </div>
                )    
            })}
        </div>
    );

}

}

但不是我想要的。即使对于实习生 renderSquare(i) 函数,我也想要另一个循环。

4个回答

要在 JSX 中呈现元素列表,您可以执行以下操作:

render() {
    return <div>
        {
            [1,2,3].map ( (n) => {
                return this.renderSquare(n)
            })

        }
    </div>;
}   

只需将您的组件数组包装到{}您的 JSX 中。

为了澄清一点,这是与以下相同的逻辑:

return <div>
    {
        [
            <h1 key="1">Hello 1</h1>,
            <h1 key="2">Hello 2</h1>,
            <h1 key="3">Hello 3</h1>
        ]           
    }
</div>;

请注意,每次渲染组件数组时,您都必须提供一个keyprop,如这里所指出的

此外,如果您只想在渲染函数中打印行值,您应该替换:

index.forEach(function(row){
    board.push(() => {
        return(
            <div>{row}</div>
        );
    });
})

和:

index.forEach( (row, index) => {
    board.push(<div key={index}>{row}</div>)
})

或者,将forEach替换pushmap

board = index.map( (row, index) => <div key={index}>{row}</div> )

编辑我使用您的代码作为基础创建了一个带有 9x9 板的小提琴:https : //jsfiddle.net/mrlew/cLbyyL27/(您可以单击单元格以选择它)

我看到你也在做 JS React 教程!这是我所做的,但我正在努力解决这个问题,因为必须有一个很好的方法来提供这些单独的密钥。

我遇到了与您遇到的相同的问题,其中 X 被绘制成 3 个正方形,发生这种情况的原因是因为当您渲染正方形时,某些“i”被复制了。因此,例如有多个“i”为 2 的方块(至少在我的问题中是这样)。

所以每个 Square 都有一个索引,对吗?[0,1,2,3,4,5,6,7,8]。

首先,我们需要找到它们之间的关系,以便我们可以将它们渲染成行!因此,在您的示例中,您有 index1 和 index2,我假设它们将指代 Board 中 Square 的 x 和 y 坐标。重写上面的数组我们得出:[{0,0}, {1,0}, {2,0}, {0,1}, {1,1}, {2,1}, {0, 2}, {1,2}, {2,2}] 使用 {x,y} 格式。我们如何使用这些值(我们将从您的 index1 和 index2 中获取,以便获得以 [0,1,2,3,4,5,6,7,8] 开头的原始值数组?

我所做的是 3 * x + y(或在循环中,3 * i + j)。这样每个方块都有一个唯一的“i”值与之关联。

在我设置我的循环后,我使用这个SO post 来正确返回我从一个单独的函数创建的元素(试图保持我的代码更清晰)。

这就是我的结果,但我需要确保正确设置密钥,这实际上是我偶然发现这篇文章的方式:

createSquares() {
  let rows = [];
  for(var i = 0; i < 3; i++){
    let squares = [];
    for(var j = 0; j < 3; j++){
      squares.push(this.renderSquare(3*i+j));
    }
    rows.push(<div className="board-row">{squares}</div>);
  }
  return rows;
}

然后我在 Board 中的渲染函数如下所示:

render() {
  return (
    <div>
      {this.createSquares()}
    </div>
  );
}

这是我在阅读这里和React JSX 内的 Loop 中的 答案后能想到的最好的

  render() {
    return (
      <div>
        {
          [...Array(3)].map((_, i) => (
            <div key={i} className="board-row">
              {
                [...Array(3)].map((_, j) => this.renderSquare(3 * i + j))
              }
            </div>
          ))
        }
      </div>
    );
  }

PS 我也在做新的React Tutorial 中的挑战=p

codepen 上的现场演示

render()函数中的嵌套循环 (注释中的解释:)

class Board extends React.Component {
  renderSquare(i) {
    return (
      <Square
        value={this.props.squares[i]}
        key={i}
        onClick={() => this.props.onClick(i)}
      />
    );
  }

  render() {
     var self = this;
    return (
      <div>
      // you can use: [...Array(3)] instead of [1,2,3]
        {[1, 2, 3].map(function(row, rowIdx) { // create rows 
          return (
            <div className="board-row" key={rowIdx}>
              {
              // you can use: [...Array(3)] instead of [1,2,3]
              [1, 2, 3].map((col, colIdx) => { // create columns
                return self.renderSquare((3 * rowIdx) + colIdx); // calculate square index
              })
              }
            </div>
          );
        })}
      </div>
    );  
  }
}