【问题标题】:React - Create nested components with loopsReact - 使用循环创建嵌套组件
【发布时间】:2017-05-30 18:11:12
【问题描述】:

我对 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>

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

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

编辑1: 以下 ma​​rklew 示例我应该能够做这样的事情

    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 个牢房里

编辑2: 我找到了解决方案:

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) 函数,我也想要另一个循环。

【问题讨论】:

    标签: javascript loops reactjs inline jsx


    【解决方案1】:

    要在 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>;
    

    请注意,每次渲染组件数组时,都必须提供 key 属性,正如 here 所指出的那样。

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

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

    与:

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

    或者,将forEachpush 替换为map

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

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

    【讨论】:

    • @MarianDiaconu 我用一个有效的小提琴更新了我的答案
    • 也许我误解了您提供的链接,但它说应该将键分配给列表项,并且通常没有说明组件数组。
    【解决方案2】:

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

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

    所以每个 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”值与之关联。

    设置循环后,我使用this 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>
      );
    }
    

    【讨论】:

      【解决方案3】:

      在阅读此处和Loop inside React JSX 的答案后,这是我能想到的最好的:

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

      附:我也在新的React Tutorial 中接受挑战。 =p

      【讨论】:

        【解决方案4】:

        Live demo on codepen

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

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

        【讨论】:

          【解决方案5】:

          我假设您正在查看 React 教程示例。正如说明中明确指出的那样,这个想法是创建两个循环,而不仅仅是一个。

          本例中的第一个循环创建了 3 行。第二个嵌套循环创建 3 个必要的列,通过 renderSquare 函数为每个位置返回一个 Square。您可能会注意到,我使用两个循环的索引来正确地将相应的索引分配给正方形。

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

          【讨论】:

          • 你能补充一些解释吗?谢谢。
          • 抱歉,@Sanyash。让我知道是否需要进一步说明。
          【解决方案6】:

          这是我的解决方案。它可能会有所帮助。

          renderSquare(i) {
              return (
                <Square
                  key={i}
                  value={this.props.squares[i]}
                  onClick={() => this.props.onClick(i)}
                />
              );
            }
          
            render() {
              
              let rows = [];
              for (let i = 0; i <= 2; i++) {
                let children = []
          
                for (let j = i * 3; j <= i * 3 + 2; j++) {
                  children.push(this.renderSquare(j))
                }
          
                rows.push(
                  <div key={i} className="board-row">
                    {children}
                  </div>
                )
              }
          
              return (
                <div>
                  {rows}
                </div>
              );
            }
          

          【讨论】:

            【解决方案7】:

            这个 sn-p 使用 map 的方式类似于我们定义嵌套循环的方式。

            const buildBoard = [0, 1, 2].map((row) => {
              return (
                <div className='board-row' key={row}>
                  {[0, 1, 2].map((col) => {
                    return this.renderSquare(row * 3 + col);
                  })}
                </div>
              );
            });
            
            return <div id='Board Container'>{buildBoard}</div>;

            【讨论】:

              【解决方案8】:

              您正在将函数推送到 board 数组。如果要渲染它们,则必须调用这些函数,例如

              {board[0]()}
              

              我准备了一个例子来解决你的问题:http://jsbin.com/hofohiy/edit?js,output

              【讨论】:

              • 我不明白这如何解决我的问题 -> 我收到一个错误:{board is not a function}
              • 哦,也许现在我明白了,当我执行 rows.push(() => { 你说我在数组中推送一个函数而不是一个反应元素?我想要推送元素我怎么能这样做?
              【解决方案9】:

              我也在编写 React 教程。感谢您的回复。我得到了这个解决方案:

              render() {
                  const rows = [];
                  for(let i = 0; i<9; i=i+3) {
                      const oneRow = [];
                      for(let j = i; j < i+3; j++) {
                          oneRow.push(this.renderSquare(j, j))
                      }
                      rows.push(<div className="board-row" key={i + 'someId'}>{oneRow}</div>)
                  }
                  return (
                      <div>
                          {rows}
                      </div>
                  );
              }
              

              我更改了 renderSquare 以设置 Square 组件的键,作为第二个参数。

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

              【讨论】:

                【解决方案10】:

                这应该可以解决您面临的问题。

                这甚至为实习生 renderSquare(i) 函数添加了另一个循环。 它可以满足您的需求,即为井字游戏显示 3 列和 3 个单元格。

                 render() {
                    let count = 0;
                    const index = [1, 2, 3];
                    return (
                      <div>
                        {index.map((v, i) => {
                          return (
                            <div key={i} className="board-row">
                              {index.map((v2, i2) => {
                                return this.renderSquare(count++);
                              })}
                            </div>
                          );
                        })}
                      </div>
                    );
                  }
                

                【讨论】:

                  【解决方案11】:

                  第一种解决方案:

                  import React from 'react';
                  import Square from './Square';
                  
                  export default
                  class Board extends React.Component {
                    render() {
                      const board2 = [];
                  
                      for (let i = 0; i < 3; i++) {
                        const s = [];
                        for (let k = 0; k < 3; k++) {
                          s[k] = <Square
                            key     ={3*i+k}
                            value   ={this.props.squares[3*i+k]}
                            onClick ={()=>this.props.onClick(3*i+k)}
                            />;
                        }
                        board2[i] = <div className="board-row" key={i}>{s}</div>;
                      }
                      ///////////////////////////////////////
                      return (
                        <div>{board2}</div>
                      );
                    }
                  }
                  

                  第二种解决方案:

                  import React from 'react';
                  import Square from './Square';
                  
                  export default
                  class Board extends React.Component {
                    render() {    
                      let board   =Array(3).fill(null);
                      let square  =Array(3).fill(null);
                  
                      const x = board.map((b,bIndex)=>{
                        return<div className="board-row" key={bIndex}>
                          {
                            square.map((s, sIndex)=>{
                              return <Square
                              key     ={3*bIndex+sIndex}
                              value   ={this.props.squares[3*bIndex+sIndex]}
                              onClick ={()=>this.props.onClick(3*bIndex+sIndex)}
                              />;
                            })
                          }
                        </div>;
                      });
                      ///////////////////////////////////////
                      return (
                        <div>{x}</div>
                      );
                    }
                  }
                  

                  正方形:

                  import React from 'react';
                  
                  export default
                  function Square(props) {
                    console.log('square render')
                    return (
                      <button className="square" onClick={props.onClick}>
                        {props.value}
                      </button>
                    );
                  }
                  

                  【讨论】:

                    【解决方案12】:
                    class Board extends React.Component {
                      renderSquare(i) {
                        return (<Square key={i} value={this.props.squares[i]} onClick={() => this.props.onClick(i)} />);
                      }
                    
                      render() {
                        let board = [];
                        for(let x = 0; x<3; x++){
                          let lis =[];
                          for(let y = 0; y<3; y++){
                            lis.push(this.renderSquare(3*x + y));
                          }
                          board.push(<div key={x}>{lis}</div>)
                        }
                        return (
                          <div>
                            {board}
                          </div>
                        );
                      }
                    }
                    

                    【讨论】:

                    • 通常只使用代码的答案是不受欢迎的。您应该在答案中添加描述:)
                    【解决方案13】:

                    我的解决办法是:

                    class Board extends React.Component {
                    
                        //range is a Sequence generator function
                        //Array.from(arrayLike[, mapFn [, thisArg]]).
                        //arrayLike - An array-like or iterable object to convert to an array
                        //mapFn - Map function to call on every element of the array
                        //thisArg - Value to use as this when executing mapFn
                        //range(0, 4, 1);  => [0, 1, 2, 3, 4] 
                    
                        range = (start, stop, step) => Array.from(
                            { length: (stop - start)/step +1 }, 
                            (_, i) => start + (i * step)
                        );
                    
                        renderSquare(i) {
                            return <Square 
                                key={i}
                                value={this.props.squares[i]} 
                                onClickChange={() => this.props.onClickChange(i)} 
                                />;
                        }
                    
                        render() {
                        let row = 3;
                        let col = 3;
                        return (
                            <div>
                                {
                                    //This generates an Array of [0, 3, 6] if row = 3 and col = 3
                                    // n is the element and i is the index of the element, i starts at 0
                                    this.range(0, row * col - 1, col).map( (n, i) => {
                                        return (
                                            <div key={i} className="board-row">
                                                {
                                                    this.range(n, (i + 1) * col - 1, 1).map( (n, i) => {
                                                    return this.renderSquare(n)
                                                    })
                                                }
                                            </div>
                                        )
                                    })
                                }
                            </div>
                        );
                    }
                    

                    【讨论】:

                      【解决方案14】:

                      从教程中更改了 Board 的代码以反映为

                      class Board extends React.Component {
                        constructor(props) {
                          super(props);
                          this.rows = Array(3).fill(null);
                        }
                        
                        renderSquare(i) {
                          return (<Square
                            key={i} 
                            value={this.props.squares[i]}
                            onClick={() => this.props.onClick(i)}
                          />);
                        }
                        
                        renderRow(row) {
                          return (
                            <div key={row} className="board-row">
                              {this.rows.map((x, col) => this.renderSquare(3*row+col))}
                            </div>
                          );
                        }
                      
                        render() {
                          return (
                            <div>
                              {this.rows.map((x, rowIndex) => this.renderRow(rowIndex))}
                            </div>
                          );
                        }
                      }
                      

                      【讨论】:

                        【解决方案15】:

                        上面提供数组的答案,破坏了循环的目的;这并不漂亮,但话说回来,React 与 JSX 也不是:

                        class Board extends React.Component {
                            
                            render() {
                                let board=[];
                                for(let row=0;row<9;row+=3) {
                                    let cols=[];
                                    for(let col=0;col<3;col++) {
                                        let i=col+row;
                                        cols.push(<Square value={this.props.squares[i]} onClick={() => this.props.onClick(i)}/>)
                                    }
                                    
                                    board.push(
                                        <div className="board-row">
                                            {cols}
                                        </div>
                                    );
                                   }
                        
                                return (
                                    <div>
                                        {board}
                                    </div>
                                );
                            }
                        }
                        

                        【讨论】:

                          猜你喜欢
                          • 2023-02-10
                          • 1970-01-01
                          • 2012-07-24
                          • 2018-03-31
                          • 1970-01-01
                          • 1970-01-01
                          • 2020-06-02
                          • 1970-01-01
                          • 2019-03-27
                          相关资源
                          最近更新 更多