An Absolute Beginner Learns React, Part III
Tags: javascript, react, beginners, tutorial
Published: 2019-04-07 15:54:48

This is a continutation of my [stream of consciousness](https://dev.to/awwsmm/an-absolute-beginner-learns-react-2j0f) [blog posts](https://dev.to/awwsmm/an-absolute-beginner-learns-react-part-ii-e15) on learning React for the first time. I'm working my way through [ReactJS.org's tutorial](https://reactjs.org/tutorial/tutorial.html) and last time, I made progress toward building a basic tic-tac-toe game. In this blog post, I'll finish it! (Hopefully!)

---

So when we left off last time, I had just coded the ability for the user to select squares. But they could only make squares into 'X'-es and there was no mechanism for anyone to win. Clearly we have a lot left to do:

![](https://thepracticaldev.s3.amazonaws.com/i/5cheffgxhasyb27bszw7.png)

Okay, so... what? This text is a bit confusing. I think it's saying that we don't want the board to have to constantly query each square for its state in order to determine if anyone has won the game. It _sounds_ like the squares will send their state to the board when they update (which should only happen once) and the board will keep track of it from that point on. But, like I said, I'm not sure, because this text isn't very clear.

So, the title of this section is "Lifting State" and this is the next block of text I see:

![](https://thepracticaldev.s3.amazonaws.com/i/6vnjub19p2gc9wuuawuk.png)

I have to read it a few times to parse it but it sounds like what it's saying is that, whenever you want two components to talk to each other, they _must_ do so through a parent component. I'm not sure why.

...or is this text (and the previous text) saying that it's a _recommended_ practice to do it this way? Is it because any child can pass its state to its parent, and any parent can set the state of the children, but children can't talk to _other_ children through the parent? Is that why "lifting state up" into the parent is encouraged?

A bit of explanation here would be really helpful.

I add this `constructor` into the `Board` to initialise the state of the board to nine empty squares:

```js
  constructor(props) {
    super(props);
    this.state = {
      squares: Array(9).fill(null)
    };
  }
```

Although, again, in the example code, there's a dangling comma at the end of the line which begins `squares: Array...`. I remove this dangling comma which I believe is a typo.

The syntax to initialise the `this.state.squares` is similar to the syntax used to initialise `this.state.value` in an individual square:

```js
    this.state = {
      value: null
    };
```

```js
    this.state = {
      squares: Array(9).fill(null)
    };
```

...except this time, instead of a single `value` in a single `Square`, we have an `Array` of `9` values, each of which we set to `null` by default. I assume.

![](https://thepracticaldev.s3.amazonaws.com/i/22yukgv2ucwvqdfvxon4.png)

I didn't even realise that's what was happening, but I see it now, yeah. Here:

```js
  renderSquare(i) {
    return <Square value={i} />;
  }
```

...when we render a square, we send it the value `i`, which is determined by its position in the grid:

```js
        <div className="board-row">
          {this.renderSquare(0)}
          {this.renderSquare(1)}
          {this.renderSquare(2)}
        </div>
```

So `i = 1, 2, 3, ...`. But the actual `render()` method within the `Square` class is:

```js
  render() {
    return (
      <button className="square"
        onClick={() => this.setState({value: 'X'})}>
        {this.state.value}
      </button>
    );
  }
```

It completely ignores the `i` passed to it, which becomes an unused part of its `state`:

```js
  constructor(props) {
    super(props);
    this.state = {
      value: null
    };
  }
```

...and sets the value to `X` with `this.setState({value: 'X'})}`, no matter the value that's passed to it. Presumably, next, we'll fix this behaviour and allow the state to be set to `X` or `O`, depending on the value passed to `renderSquare()`.

Since we've defined the state of the board in `Board.state.squares` (which we'll update in the future), we can instead pass a square's state (from that array) to the square by altering the `renderSquare()` method:

```js
  renderSquare(i) {
    return <Square value={i} />;
  }
```

becomes

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

> _Wow, this section feels a lot longer than the other ones..._

Okay, so now that the state of the game is held in `Board`, any particular `Square` cannot update the game state directly, as objects cannot directly edit the state of other objects. This next part is a bit complex.

First, if the `Square`s are no longer keeping track of the game's state, we can delete the `constructor` entirely, as all it did was set the state of that `Square`:

```js
class Square extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      value: null
    };
  }

  render() {
    return (
      <button className="square"
        onClick={() => this.setState({value: 'X'})}>
        {this.state.value}
      </button>
    );
  }
  
}
```

becomes

```js
class Square extends React.Component {

  render() {
    return (
      <button className="square"
        onClick={() => this.setState({value: 'X'})}>
        {this.state.value}
      </button>
    );
  }
  
}
```

Then, we will pass a function from `Board` to `Square` which tells the `Square` how to handle a click, so

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

becomes

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

Lines are indented for legibility and `return` must now have a `()` after it, surrounding its contents. Otherwise, JavaScript's [automatic semicolon insertion](http://www.bradoncode.com/blog/2015/08/26/javascript-semi-colon-insertion/) could break the code. (_Who thought that was a good idea?_)

This means, of course, that `Square` should be updated as well. Instead of `this.setState({value: 'X'})}`, we should use `this.props.onClick()` in the `button`'s `onClick` definition:

```js
class Square extends React.Component {

  render() {
    return (
      <button className="square"
        onClick={() => this.setState({value: 'X'})}>
        {this.state.value}
      </button>
    );
  }
  
}
```

becomes

```js
class Square extends React.Component {

  render() {
    return (
      <button className="square"
        onClick={() => this.props.onClick()>
        {this.state.value}
      </button>
    );
  }
  
}
```

Oh, and (of course), `this.state.value` should change to `this.props.value` as the state of this `Square` will be sent from the `Board` to this `Square` in its `props`:

```js
class Square extends React.Component {

  render() {
    return (
      <button className="square"
        onClick={() => this.props.onClick()>
        {this.state.value}
      </button>
    );
  }
  
}
```

becomes

```js
class Square extends React.Component {

  render() {
    return (
      <button className="square"
        onClick={() => this.props.onClick()>
        {this.props.value}
      </button>
    );
  }
  
}
```

I still don't understand how this is all going to come together, but I guess that explanation is on its way.

![](https://thepracticaldev.s3.amazonaws.com/i/ewgyuein9al512n58j19.png)

Oh, yeah, look, there it is. I again run `npm start` in the terminal and wait an excruciatingly long time for the code to run. (_Does anyone else have this problem?_) And when it does, I get an error page in the browser:

![](https://thepracticaldev.s3.amazonaws.com/i/g68xhlpsuoxk24ci0a4r.png)

What did I do?

Oh it looks like I forgot to update `{this.state.value}` to `{this.props.value}` in my code, even though I wrote it here. Let's change that and try again:

![](https://thepracticaldev.s3.amazonaws.com/i/rxc2wpowcsaajvmjvxmt.png)

Great, it worked! It was supposed to crash in that specific way, because we haven't yet defined the `onClick()` function in `this.props`.

Also, I'm reading a note in the tutorial and it looks like I've mis-named this function:

![](https://thepracticaldev.s3.amazonaws.com/i/beu2ixzh8t6wki2xuvwx.png)

So where I have `this.props.onClick()`, I should change to `this.props.handleClick()`. Let me reproduce the entire `index.js` file here for clarity:

```js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';

class Square extends React.Component {

  render() {
    return (
      <button className="square"
        onClick={() => this.props.handleClick()}>
        {this.props.value}
      </button>
    );
  }

}

class Board extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      squares: Array(9).fill(null)
    };
  }

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

  render() {
    const status = 'Next player: X';

    return (
      <div>
        <div className="status">{status}</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 {
  render() {
    return (
      <div className="game">
        <div className="game-board">
          <Board />
        </div>
        <div className="game-info">
          <div>{/* status */}</div>
          <ol>{/* TODO */}</ol>
        </div>
      </div>
    );
  }
}

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

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

I missed a few other things in the code, as well. Taking notes here and editing the code in the terminal while reading along with the tutorial can be a bit confusing. I think everything above is as it is in the tutorial to this point, so let's continue.

To get rid of that second error ("`_this.props.onClick` is not a function") and remembering that we renamed `onClick` to `handleClick`, we must now define a `handleClick` method in `Board`:

> _I'm not sure I'm really learning anything from this tutorial. More just copying-and-pasting prewritten code. I'll stick through to the end, though._

Within `Board`, we now define the `handleClick()` method:

```js
handleClick(i) {
  const squares = this.state.squares.slice();
  squares[i] = 'X';
  this.setState({squares: squares});
}
```

Before I read ahead, let me see if I can guess what this is doing. First, it's a function that takes a single parameter `i`, which is the index of the square on the board (_either `0-8` or `1-9`, I don't know if JavaScript is `0`-based or `1`-based_). It then creates a `const`ant local variable within the method which it initialises to its own `state.squares`. I have no idea why `slice()` needs to appear there if `squares` is already an array. Also, why is `squares` declared as `const` when we change the value of one of its elements in the very next line? Finally, we set the state with `setState`. It looks like variables are passed by value in JavaScript, so we have to explicitly copy the value of `squares.state` into a local variable, which we edit, then pass that edited variable back to change the state. How much of that is right?

![](https://thepracticaldev.s3.amazonaws.com/i/uuwdghujglcrx7pme3m8.png)

...okay, I'll learn about this later, I guess.

It's literally the next paragraph that begins to explain this. Why even have that "we'll explain this later" if you're going to talk about it in the next breath? Here's why they suggest doing it the way they did:

![](https://thepracticaldev.s3.amazonaws.com/i/mkcflvhcf5bhballqton.png)

The way that was natural to me was to edit the state of the `Square` directly, but the way that the tutorial recommends is to create a new object and not to mutate the existing one. The tutorial recommends keeping objects immutable as much as possible so that changes are easy to detect and the application can easily be reverted to a previous state, among other benefits.

![](https://thepracticaldev.s3.amazonaws.com/i/c2cyi49hhz1756y51v1s.png)

> _Jeez. Okay. Maybe it's me, because I don't have a really strong JavaScript / reactive front-end programming background, but this tutorial seems to jump from one concept to another with basically no segue. There doesn't really seem to be a clear goal or learning pathway in mind. I feel like I'm just learning a random concept, then copying some code, then moving on to the next thing. Not a big fan so far._

![](https://thepracticaldev.s3.amazonaws.com/i/4pwllztodlk71b6yjqhd.png)

Okay, that does actually seem easier. Since the square holds no state itself, it will be rendered by calling this function from within `Board`.

![](https://thepracticaldev.s3.amazonaws.com/i/em9b8s6d41b8lrcb4u0n.png)

Okay but why. No explanation given, we move on to the next thing.

Before we change the `renderSquare()` function in `Board`, we're going to add the ability to draw `O`s on the board, as well as `X`es. We set the initial state in the `Board`'s `constructor`:

```js
class Board extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      squares: Array(9).fill(null)
    };
  }
```

becomes

```js
class Board extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      squares: Array(9).fill(null),
      xIsNext: true
    };
  }
```

And *__again__*, there is a dangling comma at the end of `xIsNext: true`, which I have removed. Is this intentional?

So `xIsNext` is a boolean that we'll flip each time we render a square. When we rewrite `renderSquare()` (I suppose) we'll flip `xIsNext` from false to true or vice versa, and check the status of `xIsNext` before we decide to draw an `X` or an `O`. We change

```js
  handleClick(i) {
    const squares = this.state.squares.slice();
    squares[i] = 'X';
    this.setState({squares: squares});
  }
```

to

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

(Again, removing a dangling comma.)

![](https://thepracticaldev.s3.amazonaws.com/i/p3qp9m98khh8soj8m3rd.png)

Oops, typo. Let me fix that.

![](https://thepracticaldev.s3.amazonaws.com/i/3rn93umm5f0hrljxduh8.png)

Getting there! The game still doesn't declare a winner, as you can see above. I guess that's the next thing to do, but before we do that, the tutorial wants us to render a message saying who's turn it is. We add the line:

```js
    const status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
```

...to the top of the `Board`'s `render()` function (right now, it always says `X` is the next player):

![](https://thepracticaldev.s3.amazonaws.com/i/pjgke31o0jqb27kf560v.png)

I _just noticed_, too, that when I edit the `index.js` file, React automatically re-renders the page at `localhost:3000`. That's pretty neat!

Okay, last things last: how do we declare a winner?

> _I'm really running out of steam at this point so I'm glad that this section is almost over._

![](https://thepracticaldev.s3.amazonaws.com/i/a9k82w1vhi7po79kx1l7.png)

Definitely not a fan of the style of this tutorial. 0/10. Would not recommend.

I would prefer a tutorial that starts with the smallest understandable bits of code and works up from there, rather than starting with a skeleton and saying "okay, now copy and paste the contents of this to there" over and over. Ugh.

After mindlessly copying some more code...

![](https://thepracticaldev.s3.amazonaws.com/i/9jepqqfwttp3jofwwdnl.png)

...it works! But I'm not happy about it.

---

There's one more section in this tutorial but I am seriously lacking the motivation to complete it. I think I'd like to try a different tutorial or book that starts from the basics and builds on them.

I'm quitting this tutorial 75% of the way through. I feel frustrated and I don't feel like I actually learned much about React. Maybe the people at [ReactJS.org](https://reactjs.org/tutorial/tutorial.html) should consider doing some focus group testing for this tutorial because I'm sure I'm not the only person who has had this reaction.

In the comments on one of my previous posts, Kay Plößer recommended their book [React From Zero](https://www.fullstackreact.com/react-from-zero/) which sounds like it might be a bit more up my alley. I think I'll give React a second chance after I take some time to recover from this experience.