reactで碁盤アプリを作る

この記事はLivesense Advent Calendar 2017-学- 16日目です。

新卒1年目のエンジニアの @asadaman です。
最近reactを勉強し始めたので、それについて書こうと思います。
react tutorialはまるばつゲームだったので、それを少しだけ拡張して9x9の碁盤アプリを作ることにしました。
最初に断っておきますが、ひどいコードをを修正しながら完成に近づけていった過程を書いていきます。

## やること
- 9x9の碁盤
- 黒石と白石を交互に打てる
- create react app と react tutorial をベースに作る

#### あきらめたこと
- 勝敗の判断
- （相手の石を囲んだ場合に）石をとる
- typescript（当初はtypescriptで作る予定でしたが型をどうやってつければいいかわからず断念）

## やったこと
### 1. create react app でひな形をつくる

[create-react-app](https://github.com/facebookincubator/create-react-app) の Quick Overview に書いている通りですが、以下のコマンドでひな形を作ります。

```
$ npm install -g create-react-app

$ create-react-app react-go-game
```

### 2. react tutorialのコードをそのまま持ってくる
まずは真似するところからということで、自分が作りたいものに一番近い状態の [react tutorial](https://reactjs.org/tutorial/tutorial.html#taking-turns) のコード（まるばつ交互に打てるような実装が完了したところ）をそのまま持ってきました。

### 3. 9x9に拡張する
9x9の碁盤を作りたいので、該当箇所を変更します。

3x3で合計9個だったArrayは9x9で合計81個にします。
**before**

```js
squares: Array(9).fill(null),
```

**after**

```js
squares: Array(81).fill(null),
```


次に，renderの箇所を変更します。
**before**

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

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

**after**

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

    return (
      <div>
        <div className="status">{status}</div>
        <div className="board-row">
          {this.renderSquare(0)}
          {this.renderSquare(1)}
          {this.renderSquare(2)}
          {this.renderSquare(3)}
          {this.renderSquare(4)}
          {this.renderSquare(5)}
          {this.renderSquare(6)}
          {this.renderSquare(7)}
          {this.renderSquare(8)}
        </div>
        <div className="board-row">
          {this.renderSquare(9)}
          {this.renderSquare(10)}
               ...
              (中略)
               ...
          {this.renderSquare(80)}
        </div>
      </div>
    );
  }

```
81個並べるのはダルいです。（普通81個も書かないと思います。真似しないでください。）

あと、まるとばつから黒丸と白丸に変更しました。
**before**

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

**after**

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

### 4. コンポーネント化する
`renderSquare`というのが81行も並んだ残念なコードを見て悲しみにくれていると、同じチームの親切な先輩からアドバイスをもらいました。
先輩：**「reactの基本的な概念はコンポーネントを作ってそれを組み立ててビューを作るんだよ」**
（正確には忘れました）
チュートリアルにもそんなことが書いてあったなとようやく気がついた僕はちゃんと頭を使ってreactっぽいコードを書くことにしました。

四角を9個描画する`renderBoardRow`を作成しその中で`renderSquare`を呼ぶ、さらにそれを9行分描画する`renderBoard()`を作成しその中で`renderBoardRow`を呼ぶ。そうすると、あのひどく長かったrenderの箇所がスッキリしました。

```js
  render() {
    return (
      <div className="App">
        <div className="App-header">
          <h2>Go App</h2>
        </div>
        <div className="background">
	  {this.renderBoard()}
        </div>
      </div>
    );
  }
```

### 5. CSSを修正する
このままだと、9x9のマスに黒と白の丸を並べるオセロになってしまうので、画像をあてて碁盤と碁石っぽい見た目にします。

### 6. できたもの
なんとかそれっぽい感じになりました。
<img width="1280" alt="スクリーンショット 2017-12-18 22.53.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/45609/39797614-d2f8-6672-c0c8-89478cf9635e.png">
最終的なjsのコードも貼っておきます。
https://github.com/asadaman/react-go-game/blob/master/src/App.js

## 今後やりたいこと
- 今回あきらめたこと
- 棋譜記録・再生

まずはtypescriptで型をつけるところから始めたいと思います。