React - Create nested components with loops

后端 未结 14 1537
情话喂你
情话喂你 2020-12-30 01:27

I have a little issue with React. I can\'t create a nested component with a for loop. What I want to do is create 9 cells of a table and then create 3 rows with 3 cells for

相关标签:
14条回答
  • 2020-12-30 02:07

    Changed the code of the Board from the tutorial to reflect as

    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>
        );
      }
    }
    
    0 讨论(0)
  • 2020-12-30 02:11

    This should resolve the problem your facing.

    This adds another loop even for the intern renderSquare(i) function. It does what you want i.e. display 3 columns with 3 cells for the tic tac toe game.

     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>
        );
      }
    
    0 讨论(0)
  • 2020-12-30 02:12

    I'm working on the React tutorial also. Thanks for your responses. I got to this solution:

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

    Where I changed renderSquare to set a key for the Square component, as the second argument.

    renderSquare(i, key) {
        return (
            <Square
                value={this.props.squares[i]}
                onClick={() => this.props.onClick(i)}
                key={key}
            />
        );
    }
    
    0 讨论(0)
  • 2020-12-30 02:15

    To render a list of elements inside JSX, you can do something like that:

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

    Just wrap your array of components into {} in your JSX.

    To clarify a bit, this is the same logic of:

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

    Note that everytime you render an array of components, you must provide a key prop, as pointed here.

    Also, if you want simply print row value in your render function, you should replace:

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

    with:

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

    or, yet, replacing forEach and push with map:

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

    EDIT I created a fiddle with a 9x9 board using your code as a base: https://jsfiddle.net/mrlew/cLbyyL27/ (you can click on the cell to select it)

    0 讨论(0)
  • 2020-12-30 02:17

    Live demo on codepen

    Nested loops in render() function (explanation in comments:)

    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>
        );  
      }
    }
    
    0 讨论(0)
  • 2020-12-30 02:18

    I see you too are doing the JS React tutorial! Here's what I did, but I'm working on this because there has to be a good way to give each of these individual keys.

    I ran into the same issue you were running into where the X's were drawn into 3 squares, and the reason that happens is because when you were rendering squares, some of the "i's" were duplicated. So there were multiple Squares with the "i" of 2 for example (at least that was the case in my issue).

    So each Square has an index right? [0,1,2,3,4,5,6,7,8].

    First we need to find how these are related in a way that we can render them into rows! So, in your example you have index1 and index2, which I assume will refer to the x and y coordinates of the Square in the Board. Re-writing the array above we come to: [{0,0}, {1,0}, {2,0}, {0,1}, {1,1}, {2,1}, {0,2}, {1,2}, {2,2}] using {x,y} format. How can we use these values (which we would get from your index1 and index2 in order to get the original array of values that we started with [0,1,2,3,4,5,6,7,8]?

    What I did was 3 * x + y (or in a loop, 3 * i + j). This way each square has a unique "i" value associated with it.

    After I set up my loops I used this SO post to correctly return the elements I created from a separate function (in a poor attempt to keep my code cleaner).

    This is what I ended up with, but I need to make sure to set the keys correctly which is actually how I stumbled onto this 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;
    }
    

    Then my render function in Board looks like this:

    render() {
      return (
        <div>
          {this.createSquares()}
        </div>
      );
    }
    
    0 讨论(0)
提交回复
热议问题