1

Answer which tries to do a similar thing to me: https://stackoverflow.com/a/45785715/8126531

Hi, I'm doing the ReactJS tutorial here and I'm basically at the part where it asks to replace:

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

with 2 loops to make the squares instead of hardcoding it.

Conceptually, I don't know if I've got this wrong but, I've been trying to push all the elements into an array and then having it rendered like this:

render() {
    return (
        <div>{ this.createBoard(3, 3) }</div>
    );
}

createBoard(rows, columns) {
    let htmlBlock = [];
    for (let i = 0; i < columns; i++) {
        htmlBlock.push(<div className="board-row">);
        for (let j = 0; j < rows; j++) {
            htmlBlock.push(this.renderSquare(j));
        }
        htmlBlock.push(</div>);
    }
    return htmlBlock;
}

but I get an error in the console saying semi-colon after "rows" is an unexpected token. If I push the elements to htmlBlock as a string then the output is exactly what I want except in the console it's a literal string and not HTML.

Can someone tell me why I have this error or if I've got it conceptually wrong and I should be doing it a different way?

Cheers.

btw not sure if it's relevant but I'm using webpack and the jsx files are being transpiled and bundled.

[SOLVED]: Thanks for the responses by everybody. Thanks to user "emma" I've managed to make it work. I think the problem is that you can't push an "incomplete" html block to the array and have it rendered. Below is the changes I've made:

createBoard(rows, columns) {
    let htmlBlock = [];
    for (let i = 0; i < columns; i++) {
        // htmlBlock.push(<div className="board-row">);
        let test = [];
        for (let j = 0; j < rows; j++) {
            test.push(this.renderSquare(j));
        }
        htmlBlock.push(<div> { test }</div>);
    }
    return htmlBlock;
}

Thanks again guys!!

4 Answers4

0

You can't push <div> and </div> separately. You should instead make another row list inside the top loop, then after everything has been added to the row, you can push <div>{row}</div> to htmlBlock.

emma
  • 329
  • 4
  • 11
  • 1
    Thank you so much!! You rock! I did what you said and it works. I guess the takeaway lesson is that you can't push partially complete divs to an array and have it rendered. I've added an edit on my main post to show the updated code, thanks again dudette. –  Nov 03 '17 at 16:38
0

The best way to do it is to split logic into two functions. One creates rows, and the another one adds cells to each row. Here's an example how you can do it.

class Board extends React.Component {

  createCells(cols) {
    const result = [];

    for (let i = 0; i < cols; i++) {
      result.push(<div key={"col-" + i} className="column">Cell</div>)
    }

    return result;
  }

  createBoard(rows, cols) {
    const result = [];

    for (let i = 0; i < rows; i++) {
      result.push(<div key={"row-" + i} className="row">{this.createCells(cols)}</div>)
    }

    return result;
  }

  render() {
    return (
        <div className="board">
          { this.createBoard(3, 3) }
        </div>
      )
   }
}

By the way, never forget 'key' attribute when render arrays in react.

Taras Polovyi
  • 438
  • 4
  • 10
0

Since JSX only allows expressions and for-loops are not expressions they get a little awkward to use alongside JSX.

You can create Arrays filled with null and map over those instead, like so:

function emptyArray(n) {
  return new Array(n).fill();
}

class Board extends React.Component {
    createBoard(rows, columns) {
        return emptyArray(rows).map((_, i) => (
            <div key={i} className="board-row">
                {emptyArray(columns).map((_, j) => (
                    <span key={j} className="board-column">
                        - row {i + 1}, column {j + 1} -
                    </span>
                ))}
            </div>
        ));
    }

    render() {
        return (
            <div className="board">
                { this.createBoard(3, 3) }
            </div>
        )
   }
}
Erik Inkapööl
  • 378
  • 2
  • 11
-1

You can use reactjs dangerouslySetInnerHTML property

render() {
    return (
        <div dangerouslySetInnerHTML={{ __html: this.createBoard(3, 3) }}></div>
    );
}

Now you can use string when push html string to htmlBlock variable.

  • Thanks for your answer, I would like to know what the best practice is though. –  Nov 03 '17 at 16:45