チュートリアルを参考に15分でReactざっくり理解

# 参考
https://ja.reactjs.org/tutorial/tutorial.html

https://ja.reactjs.org/docs/hello-world.html

---

# 前提
- npmがインストール済み

# 入れておくと便利
- [シンタックスハイライティング](https://babeljs.io/docs/en/editors/)
- [ブラウザのReact Devtools拡張機能](https://ja.reactjs.org/tutorial/tutorial.html#developer-tools)

---

# この解説の最終目標
チュートリアルの三目並べが完成するまで。（チュートリアルには履歴機能の実装もあるが、ここでは範囲外）

---

# Reactプロジェクト作成から実行
```bash
npx create-react-app hello-react
cd hello-react
npm start
```

---

# チュートリアルの初期状態のファイルを用意
↓プロジェクト作成直後から以下手順（

1. `src/`の中身をすべて削除
1. `src/index.css`を作成して、[ここの CSS コード](https://codepen.io/gaearon/pen/oWWQNa?editors=0100)を記入する。
1. `src/index.js`を作成して、[ここの JS コード](https://codepen.io/gaearon/pen/oWWQNa?editors=0010)を記入する。（そのままだとエラーが出るので次もやること）
1. `src/index.js`ファイルの先頭に以下の 3 行のコードを加える。

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

---

## 初期状態の解説
React描画処理抜粋

```js
ReactDOM.render(
  <Game />,
  document.getElementById('root')
);
```
- `ReactDOM.render`が描画の起点となる。[公式解説](https://ja.reactjs.org/docs/hello-world.html)


Reactコンポーネント抜粋

```jsx
class Square extends React.Component {
  render() {
    return (
      <button className="square">
        {/* TODO */}
      </button>
    );
  }
}
```

- Reactコンポーネント（画面を構成する部品単位）は`React.Component`を継承したクラスで記述する（クラス意外にも表現方法はある）[公式解説](https://ja.reactjs.org/docs/components-and-props.html)
- 一見HTMLのような`<button className="square">{/* TODO */}</button>`はJSXと呼ぶ（実態はjavascriptの拡張構文で記述されたオブジェクト）[公式解説](https://ja.reactjs.org/docs/introducing-jsx.html)
- JSXは普通のJavascriptオブジェクトなので以下の`renderSquare`メソッドのように戻り値にして別のJSXに差し込むこともできる。

```jsx
class Board extends React.Component {
  renderSquare(i) {
    return <Square />;
  }

  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>
    );
  }
}
```

---

# Reactコンポーネントにデータを渡す

## `Board`クラスの`renderSquare`メソッドを以下のように書き換える

```diff_jsx
class Board extends React.Component {
  renderSquare(i) {
-   return <Square />;
+   return <Square value={i} />;
  }
}
```

- JSXでは`{}`（中括弧）内にJavascriptが記述できる。[公式解説](https://ja.reactjs.org/docs/introducing-jsx.html#embedding-expressions-in-jsx)
- HTML属性（`<Square value={i} />`の`value`）のようにしてReactコンポーネントに値を渡せる。[公式解説](https://ja.reactjs.org/docs/components-and-props.html)

---

## `Square`クラスの`render`メソッドを以下のように書き換える

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

- `this.props`で渡された値にアクセスできる。[公式解説](https://ja.reactjs.org/docs/components-and-props.html)

---

# イベント処理の追加
## `Square`クラスの`render`メソッドを以下のように書き換える

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

- イベントには関数を渡す（`onClick={alert('click')}`のようにしてその場で実行しないように注意）。[公式解説](https://ja.reactjs.org/docs/handling-events.html)

# 状態を持つ
## `Square`クラスを以下のように書き換える

```diff_jsx
class Square extends React.Component {
+ constructor(props) {
+   super(props);
+   this.state = {
+     value: null,
+   };
+ }

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

- Reactコンポーネントは`this.state`で値を保持できる（コンストラクタにて初期化）。[公式解説](https://ja.reactjs.org/docs/state-and-lifecycle.html#adding-local-state-to-a-class)
- コンストラクタでは最初に`super(props)`を呼び出す必要がある。[公式解説](https://ja.reactjs.org/docs/state-and-lifecycle.html#adding-local-state-to-a-class)
- `this.state`を書き換える場合は`this.setState`メソッドを使う。[公式解説](https://ja.reactjs.org/docs/state-and-lifecycle.html#adding-lifecycle-methods-to-a-class)
- `this.setState`メソッドを起点に画面の再描画が行われる。[公式解説](https://ja.reactjs.org/docs/state-and-lifecycle.html#adding-lifecycle-methods-to-a-class)
- `this.state`の直接変更では再描画されない。[公式解説](https://ja.reactjs.org/docs/state-and-lifecycle.html#do-not-modify-state-directly)

---

# 状態管理がしやすいようにリファクタリング（Stateのリフトアップ）

```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={i} />;
+   return (
+     <Square
+       value={this.state.squares[i]}
+       onClick={() => this.handleClick(i)}
+     />
+   );
  }
```

```diff_jsx
class Square extends React.Component {
- constructor(props) {
-   super(props);
-   this.state = {
-     value: null,
-   };
- }
  render() {
    return (
-     <button className="square" onClick={() => this.setState({value: 'X'})}>
+     <button className="square" onClick={() => this.props.onClick()} >
-       {this.state.value}
+       {this.props.value}
      </button>
    );
  }
}
```

- 複数の子要素が互いにデータを連携するときは親でデータを管理したほうが良い。[公式解説](https://ja.reactjs.org/docs/lifting-state-up.html)
- カスタムコンポーネントのイベント（`onClick`）は`this.props`でアクセスできる（データ渡しと変わらない）。
- 標準コンポーネント（`button`等）のイベントは[こちら](https://ja.reactjs.org/docs/events.html)。
- 注意：`setState`メソッドはイミュータブルなオブジェクトが求められる。[公式解説](https://ja.reactjs.org/tutorial/tutorial.html#why-immutability-is-important)

---

# よりシンプルなコンポーネントの記述（関数コンポーネント）

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

- `render`メソッドだけならクラスではなく関数としてコンポーネントを記述できる。[公式解説](https://ja.reactjs.org/docs/components-and-props.html#function-and-class-components)
- `this.props`は引数の`props`に置き換わる。[公式解説](https://ja.reactjs.org/docs/components-and-props.html#function-and-class-components)

---

# 三目並べを完成させる

勝利判定関数は任意の場所に追加

```diff_jsx
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;
}
```


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

  handleClick(i) {
    const squares = this.state.squares.slice();
+   if (calculateWinner(squares) || squares[i]) {
+     return;
+   }
+   squares[i] = this.state.xIsNext ? 'X' : 'O';
    this.setState({
      squares: squares,
+     xIsNext: !this.state.xIsNext,
    });
  }
...

  render() {
+   const winner = calculateWinner(this.state.squares);
+   let status;
+   if (winner) {
+     status = 'Winner: ' + winner;
+   } else {
+     status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
+   }

```