Q:

Issue understanding flexbox formatting

I just finished the basic react tic tac toe tutorial and I modified the base code so I can dynamically generate n x n tic tac toe grids. Currently I'm using flexbox to format my "grid" of buttons and I'm running into an issue where flexbox column appears to be adding a margin between entities. I'm not sure why this is the case. Additionally, when I click on every element in a row, react rerenders the entire row with the correct margins. Below is my css and javascript.

function Square(props) {
  return (
    <button className="square" onClick={props.onClick}>
      {props.value}
    </button>
  );
}

class Board extends React.Component {
  // essentially these are fields that store the state of the board
  constructor(props) {
    super(props);
    this.state = {
      squares: Array(16).fill(null),
      xIsNext: true
    };
  }

  // generate row
  generateRow(j) {
    var i;
    var columns = 4;
    var row = [];

    for (i = 0; i < columns; i++) {
      row.push(
        <div key={i + columns * j}> {this.renderSquare(i + columns * j)} </div>
      );
    }
    return row;
  }

  // create board
  renderBoard() {
    var i;
    var rows = 4;
    var board = [];
    for (i = 0; i < rows; i++) {
      board.push(<div className="board-row"> {this.generateRow(i)}</div>);
    }
    return board;
  }

  handleClick(i) {
    const squares = this.state.squares.slice();
    if (squares[i]) {
      return;
    }
    squares[i] = this.state.xIsNext ? "X" : "O";
    this.setState({
      squares: squares,
      xIsNext: !this.state.xIsNext
    });
  }

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

  render() {
    let status;
    status = "Next player " + (this.state.xIsNext ? "X" : "O");

    return (
      <div>
        <div className="status">{status}</div>
        {this.renderBoard()}
      </div>
    );
  }
}

class Game extends React.Component {
  render() {
    return (
      <div className="game">
        <div className="game-board">
          <Board />
        </div>
      </div>
    );
  }
}

// ========================================

ReactDOM.render(<Game />, document.getElementById("root"));
body {
  font: 14px "Century Gothic", Futura, sans-serif;
  margin: 20px;
}

ol,
ul {
  padding-left: 30px;
}

.status {
  margin-bottom: 10px;
}

.square:focus {
  outline: none;
}

.kbd-navigation .square:focus {
  background: #ddd;
}

.game-info {
  margin-left: 20px;
}

.game-board {
  display: flex;
  flex-direction: column;
}

.board-row {
  display: flex;
  flex-direction: row;
  margin-bottom: -1px;
}

.square {
  background: #fff;
  border: 1px solid #999;
  font-size: 24px;
  font-weight: bold;
  line-height: 34px;
  height: 40px;
  padding: 0;
  text-align: center;
  width: 40px;
  margin-right: -1px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Image of the issue

A:

One effective way of debugging your layout is examining your elements' dimensions.

As you can see in the images, the button's parent div has a higher height of 2 pixels greater than the button. This is because of the additional size generated by the inline-block (button) element's borders. To address this, I simply assigned button a display: block CSS property.

function Square(props) {
  return (
    <button className="square" onClick={props.onClick}>
      {props.value}
    </button>
  );
}

class Board extends React.Component {
  // essentially these are fields that store the state of the board
  constructor(props) {
    super(props);
    this.state = {
      squares: Array(16).fill(null),
      xIsNext: true
    };
  }

  // generate row
  generateRow(j) {
    var i;
    var columns = 4;
    var row = [];

    for (i = 0; i < columns; i++) {
      row.push(
        <div key={i + columns * j}> { this.renderSquare(i + columns * j) } </div>
      );
    }
    return row;
  }

  // create board
  renderBoard() {
    var i;
    var rows = 4;
    var board = [];
    for (i = 0; i < rows; i++) {
      board.push(<div className="board-row"> {this.generateRow(i)}</div>);
    }
    return board;
  }

  handleClick(i) {
    const squares = this.state.squares.slice();
    if (squares[i]) {
      return;
    }
    squares[i] = this.state.xIsNext ? "X" : "O";
    this.setState({
      squares: squares,
      xIsNext: !this.state.xIsNext
    });
  }

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

  render() {
    let status;
    status = "Next player " + (this.state.xIsNext ? "X" : "O");

    return (
      <div>
        <div className="status">{status}</div>
        {this.renderBoard()}
      </div>
    );
  }
}

class Game extends React.Component {
  render() {
    return (
      <div className="game">
        <div className="game-board">
          <Board />
        </div>
      </div>
    );
  }
}

// ========================================

ReactDOM.render(<Game />, document.getElementById("root"));
body {
  font: 14px "Century Gothic", Futura, sans-serif;
  margin: 20px;
}

ol,
ul {
  padding-left: 30px;
}

.status {
  margin-bottom: 10px;
}

.square:focus {
  outline: none;
}

.kbd-navigation .square:focus {
  background: #ddd;
}

.game-info {
  margin-left: 20px;
}

.game-board {
  display: flex;
  flex-direction: column;
}

.board-row {
  display: flex;
  flex-direction: row;
  margin-bottom: -1px;
}

.square {
  background: #fff;
  border: 1px solid #999;
  font-size: 24px;
  font-weight: bold;
  line-height: 34px;
  height: 40px;
  padding: 0;
  text-align: center;
  width: 40px;
  margin-right: -1px;
  display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>

