【React】公式のチュートリアルをやってみる～④stateのリフトアップ

[【React】公式のチュートリアルをやってみる～③propsとstate](https://qiita.com/asahina820/items/661f95434e6a6c73fa20) の続きです。
勝利したプレイヤーを判定できるように、9個のマス目の値を1か所で管理します。

## 親コンポーネントで状態を管理する
### Boardコンポーネントにthis.state の初期状態を設定するコンストラクタを追加する

```diff_jsx
class Board extends React.Component {
  // コンストラクタ
+ constructor(props) {
+   super(props);
+   this.state = {
+     squares: Array(9).fill(null),
+   }
+ }
  renderSquare(i) {
    return <Square value={i}/>;
  }
  render() {
    (略)
  }
}
```

- 9個のスロットにnullが入った配列が生成され、squaresに格納される
    - ゲームが進むにつれ、配列の中身にX、Oが入るようにする
    - 最初の配列の中身は以下の通り
```
(9) [null, null, null, null, null, null, null, null, null]
0: null
1: null
2: null
3: null
4: null
5: null
6: null
7: null
8: null
length: 9
```
    

### BoardコンポーネントからSquareコンポーネントに表示用の値を渡す

```diff_jsx
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]}/>
    );
  }
  render() {
    (略)
  }
}
```
- Squareコンポーネントを呼び出し、そのときに props として`{value: this.state.squares[i]}`を渡す
    - 配列`squares`のi番目に格納されているデータが渡される

### Boardコンポーネントでイベントハンドラーを定義してSquareコンポーネントに渡す

```diff_jsx
class Board extends React.Component {
  // コンストラクタ
  constructor(props) {
    super(props);
    this.state = {
      squares: Array(9).fill(null),
    }
  }
+ handleClick(i) {
+   const squares = this.state.squares.slice();
+   squares[i] = 'X';
+   this.setState({squares: squares});
+ }
  renderSquare(i) {
    return (
      <Square 
        value={this.state.squares[i]}
+       onClick={() => this.handleClick(i)}
      />
    );
  }
  render() {
    (略)
  }
}
```

- BoardコンポーネントからSquareコンポーネントに`handleClick`関数を渡す
    - Reactでは、イベントを表すpropsにはon、イベントを処理するメソッドにはhandleという名前を付けるのが慣習となっている
- `handleClick`では、配列`squares`のi番目のデータに対してXを代入し、squaresを更新する
    - 現在の配列を直接変更するのではなく、`slice()`を使って 配列`square`のコピーを作成してから配列を置き換えている
        - このように、変更を加えた新しいデータのコピーを使ってデータを置き換えることを、イミュータビリティ（immutability; 不変性）という
        - 直接データのミューテート（データの書き換え）をしないことで、巻き戻し機能の実装が可能になったり、変更を検出しやすくなるといった利点がある



## 子コンポーネントで親コンポーネントから受け取ったオブジェクトを反映する
### Squareコンポーネントで、Boardコンポーネントから受け取った関数を実行できるようにする

```diff_jsx
class Square extends React.Component {
  render() {
    return (
      <button 
        className="square" 
+       onClick={() => this.props.onClick()}
      >
        {this.state.value}
      </button>
    );
  }
}
```

- クリックイベントに、受け取った`handleClick`関数を設定する
    - i番目のマスをクリックしたときに、配列`squares`のi番目にXが代入され、squaresが更新される

### Squareコンポーネントで、Boardコンポーネントから受け取った表示用の値を表示する

```diff_jsx
class Square extends React.Component {
  render() {
    return (
      <button 
        className="square" 
        onClick={() => this.props.onClick()}
      >
+       {this.props.value}
      </button>
    );
  }
}
```
- 配列`squares`のi番目のデータを表示する
    - 現在の状態だと、クリックされていないマスは何も表示されず(null), クリックされたマスはXが表示される

![ReactApp5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2667439/61b94016-f620-7d2f-468b-c944283e855c.png)

マスを押したらマスにXが表示されるようになりました～
配列`squares`にもXが格納されています。
```
(9) [null, null, 'X', null, 'X', 'X', null, null, null]
0: null
1: null
2: "X"
3: null
4: "X"
5: "X"
6: null
7: null
8: null
length: 9
```

## 参考文献
- https://ja.reactjs.org/tutorial/tutorial.html
- https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/Array
- https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/fill
- https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/slice