1

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

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
joe
  • 13
  • 4

2 Answers2

1

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

enter image description here enter image description here

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>
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
95faf8e76605e973
  • 13,643
  • 3
  • 24
  • 51
0

I think I've reproduced your markup output here and I don't see the issue you're having. I suspect there's a CSS rule somewhere that's not represented in your example; something adding a bottom margin to buttons maybe?

Have you inspected it via the browser's dev tools?

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;
}
<div class="game">
<div class="game-board">
  <div class="board-row">
    <button class="square">1</button>
    <button class="square">2</button>
    <button class="square">3</button>
    <button class="square">4</button>
  </div>
  <div class="board-row">
    <button class="square">1</button>
    <button class="square">2</button>
    <button class="square">3</button>
    <button class="square">4</button>
  </div>
  <div class="board-row">
    <button class="square">1</button>
    <button class="square">2</button>
    <button class="square">3</button>
    <button class="square">4</button>
  </div>
  <div class="board-row">
    <button class="square">1</button>
    <button class="square">2</button>
    <button class="square">3</button>
    <button class="square">4</button>
  </div>
</div>
</div>
ray
  • 26,557
  • 5
  • 28
  • 27
  • I agree that it's probably due to a bottom margin being added somehow. When you say inspect via the browser's dev tools, do you mean inspect page or something else? – joe Aug 22 '20 at 05:46