React is all about encouraging the ‘statelessness’ of React components. It makes for more straightforward code and makes it easier to track down problems. I wanted to explore this side of React more as my previous experiments have relied heavily on state, so I ended up settling on an interactive Sudoku game (this makes for a great hacker school project wink wink). Breaking down the game into React components was a pretty straightforward process:

  1. <SudokuBoard> - a 3x3 grid of 9 segments (81 cells) and a collapsable “number pad”. All of the transitive data goes here as state properties and each “cell” or element in the array of arrays are objects with certain properties (ex. if the cell is editable, the number it has or is actively selected). It also holds onto the object that pertains to an active cell.

  2. <Segment> - a 3x3 grid of 9 cells. This merely passes on SudokuBoard’s functions to the individual cells and their respective properties. It does nothing else.

  3. <Cell> - Contains an integer that the user may/may not input. User events (onKeyDown, onClick) are triggered here. Click on a square it renders it active (so long as it’s editable). Type a number to fill the cell or use the delete/backspace key to remove.

Below are the functions that SudokuBoard uses to pass down to each cell. Control of the board is centered on these two functions:

handleNumberSelect: function(e, cell) {

  // this handles the onKeyPress event;
  // a digit is permitted, as is backspace (for deletion).

  var board = this.state.board;

  if (e.which === 8) {
    board[cell.loc.x][cell.loc.y].number = 0;
  } else if (_.isNaN(cell.number)) {
    // an invalid entry - a non-number, non-backspace key press.
    return;
  } else {
    // an outside function that checks to see if
    // the move is a valid one by examining the board.
    if (cellChecker(board, cell)) {
      board[cell.loc.x][cell.loc.y].number = cell.number;
    }
  }
  // two of the above conditionals force a change on the board,
  // and so setState reflects that.
  this.setState({ board: board })
},

makeCellActive: function(e, cell) {
  // this relates to the onClick event,
  // and simply highlights a cell that is editable
  // (default numbers are not editable, as that would be cheating!)
  var board = this.state.board;
  var prevCell = this.state.activeCell;

  if (prevCell.isActive) {
    prevCell.isActive = false;
    board[prevCell.loc.x][prevCell.loc.y] = prevCell;
  }

  var activeCell = board[cell.loc.x][cell.loc.y];
  activeCell.isActive = true;
  board[cell.loc.x][cell.loc.y] = activeCell;
  // as before, the board is altered somewhat,
  // and so setState forces it to re-render to reflect the change.
  this.setState({ board: board, activeCell: activeCell })
}

Here’s the render function for Cell.

render: function() {
  var num = this.props.number === 0 ? "" : this.props.number;
  var style = { backgroundColor: this.props.isActive ? "#b4cdcd" : "#bbbbbb" };
  return (
    <div onClick={this.makeCellActive}>
      <div style={style} className='game-cell'>
        {num}
        <input className='cell-placeholder'
            style={ {opacity: "0"} }
            value={num}
            onKeyDown={this.selectNumber}
            type='text'
        ></input>
      </div>
    </div>
  )
}

Anyway, this was a lot of fun to do. Major props to Will Sommers for helping me out with this.