2

I decided to learn React and started with the official tutorial. All is good until I get to this state of my code. The problem seems to be about property squares of current in the render function of Game component which is defined but I'm not sure why it's flagged as an error

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

class Board extends React.Component {
  renderSquare(i) {
    return <Square value = {this.props.squares[i]} onClick = {() => this.props.onClick(i)} />;
  }
  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>
    );
  }
}

class Game extends React.Component {
  constructor() {
    super();
    this.state = {
      history : [{
        squares : Array(9).fill(null)  
      }],
      xIsNext : true
    };
  }
  handleClick(i){
    const history = this.state.history.slice(0, this.state.stepNumber);
    const current = history[this.state.stepNumber];
    const squares = current.squares.slice();
    if(calculateWinner(squares) || squares[i]) {
      return;
    }
    squares[i] = this.state.xIsNext ? 'X' : 'O';
    this.setState({
      history : history.concat([{
        squares : squares
      }]),
      xIsNext : !this.state.xIsNext,
      stepNumber : 0,
    });
  }
  jumpTo(step){
    this.setState({
      stepNumber : step,
      xIsNext : (step % 2) ? false : true,
    });
  }
  render() {
    const history = this.state.history;
    const current = history[this.state.stepNumber];
    const winner = calculateWinner(current.squares);
    let status;
    if(winner) {
      status = 'Winner : ' + winner;
    }
    else {
      status = 'Next Player : ' + (this.state.xIsNext ? 'X' : 'O');
    }
    const moves = history.map((step, move) => {
      const desc = move ? 'Move #' + move : 'Game start';
      return (
        <li key = {move}>
          <a href="#" onClick={() => this.jumpTo(move)}>{desc}</a>
        </li>
      );
    });

    return (
      <div className="game">
        <div className="game-board">
          <Board 
            squares = {current.squares}
            onClick = {(i) => this.handleClick(i)}
          />
        </div>
        <div className="game-info">
          <div>{status}</div>
          <ol>{moves}</ol>
        </div>
      </div>
    );
  }
}

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

ReactDOM.render(
  <Game />,
  document.getElementById('container')
);

function calculateWinner(squares) {
  const lines = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6],
  ];
  for (let i = 0; i < lines.length; i++) {
    const [a, b, c] = lines[i];
    if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
      return squares[a];
    }
  }
  return null;
}

And this is the error I get

TypeError: Cannot read property 'squares' of undefined
    at Game.render (pen.js:208:41)
    at ReactCompositeComponentWrapper._renderValidatedComponentWithoutOwnerOrContext (https://cdnjs.cloudflare.com/ajax/libs/react/0.14.7/react-with-addons.js:6336:34)
    at ReactCompositeComponentWrapper._renderValidatedComponent (https://cdnjs.cloudflare.com/ajax/libs/react/0.14.7/react-with-addons.js:6356:32)
    at ReactCompositeComponentWrapper.wrapper [as _renderValidatedComponent] (https://cdnjs.cloudflare.com/ajax/libs/react/0.14.7/react-with-addons.js:12879:21)
    at ReactCompositeComponentWrapper.mountComponent (https://cdnjs.cloudflare.com/ajax/libs/react/0.14.7/react-with-addons.js:5969:30)
    at ReactCompositeComponentWrapper.wrapper [as mountComponent] (https://cdnjs.cloudflare.com/ajax/libs/react/0.14.7/react-with-addons.js:12879:21)
    at Object.mountComponent (https://cdnjs.cloudflare.com/ajax/libs/react/0.14.7/react-with-addons.js:13613:35)
    at ReactCompositeComponentWrapper.mountComponent (https://cdnjs.cloudflare.com/ajax/libs/react/0.14.7/react-with-addons.js:5974:34)
    at ReactCompositeComponentWrapper.wrapper [as mountComponent] (https://cdnjs.cloudflare.com/ajax/libs/react/0.14.7/react-with-addons.js:12879:21)
    at Object.mountComponent (https://cdnjs.cloudflare.com/ajax/libs/react/0.14.7/react-with-addons.js:13613:35)
2
  • 1
    Did you try to add stepNumber : 0 to the state inside the constructor of the Game component ? Commented Dec 14, 2016 at 12:10
  • 1
    @DavidDomain Silly me Commented Dec 26, 2016 at 17:54

1 Answer 1

4

So in your Game render function you start with these three lines of code

const history = this.state.history;
const current = history[this.state.stepNumber];
const winner = calculateWinner(current.squares);

However, in your Game constructor function, you do not set stepNumber in the state:

constructor() {
    super();
    this.state = {
        history : [{
            squares : Array(9).fill(null)  
        }],
        xIsNext : true
    };
}

Therefore, when you do

const current = history[this.state.stepNumber]

what you are essentially doing is

const current = history[undefined]

which means when you do

const winner = calculateWinner(current.squares)

you are actually doing

const winner = calculateWinner(undefined.squares)

and there is your problem. You need to set stepNumber in your state in the constructor function.

Sign up to request clarification or add additional context in comments.

1 Comment

Is there a way I can use a debugger along with the tutorial to figure out these errors since understanding the errors thrown seem to be hard?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.