Reactでサイコロを作ってみた

# はじめに

いまさらですがReact（react.js）をはじめてみました。勉強会の宿題で、サイコロのアプリを作ってこい、とのことなので、勉強も兼ねてやってみました。

本当に基礎の基礎的なことは省いているので、ものすごく丁寧には解説してません。

できたのが、[これ](https://codesandbox.io/s/pwz18wjq40)です。←クリック！

# 用意

ローカルPC上に、`create-react-app`してもいいのですが、サクッと作りたかったので、今回はブラウザ上で手軽にReact環境が作れるエディタの[codesandbox](https://codesandbox.io/)上に作りました。

<img width="1122" alt="スクリーンショット 2018-12-03 00.11.46.png" src="https://qiita-image-store.s3.amazonaws.com/0/14191/d839ce96-86c1-2a3c-8c79-29e5b8d0f5da.png">


<img width="1680" alt="スクリーンショット 2018-12-02 21.11.25.png" src="https://qiita-image-store.s3.amazonaws.com/0/14191/c3e8794d-eaa7-2ffa-3f91-4fc976cf9e43.png">

# 手順

index.jsにあるコードを一旦、全部消して、必要なものだけ書いていきます。

まず、ES2015のシンタックスを使ってJSのモジュールを読み込みます。

```js
import React from "react";
```

`React`という名前で`"react"`というモジュールから読み込みを行う、と言う意味。こうすることで、このファイルの中で定義してない関数や変数やクラスとかが使えるようになる（`render`とかが使えるようになります）。

もうひとつ読み込みます。`"react-dom"`というパッケージから`render`を読み込みます。

```js
import { render } from "react-dom";
```

そして、上記で読み込んだ`render`を早速render関数（メソッド）を使ってみます。シンタックスは以下の通り

```js
render(JSX, target DOM Element)
```

実際にはこう書きました。

```js
render(<DiceApp />, document.getElementById("root"));
```

こう書くことで、HTML上にある`#root`のDOMに、Reactで作ったコンポーネントをレンダリングできます。

現状こんな感じです。

```js:index.js
import React from "react";
import { render } from "react-dom";

render(<DiceApp />, document.getElementById("root"));
```

でも、このままだと、DiceAppが定義されておらずReferenceErrorになります。
第一引数である`ReactComponent`の`<DiceApp />` の説明は後述します。

あ、ちなみに、この第一引数には以下のような要素などが入ります。

- `ReactElement`←JSのオブジェクト
    - クラスの実体といってもいい
- `ReactComponent`←JSのクラス(コンストラクタ関数)
    - 何らかの入力に応じてオブジェクト（実体）ができます

ちなみに...`ソースコード→マシン語`変換のコンパイルではなく、ソースコード（JSX）からソースコード（JSのObject）への変換だからトランスコンパイルなのですね。

参考：http://js.studio-kingdom.com/react/glossary/#react_components

## ReactComponent　を作る

まず、renderメソッドの第一引数にReactComponentを入れる場合、最初の文字は大文字、`< />`で囲うというルールがあります。

次に、stateを持ったReactのクラスで書くコンポーネント（ReactComponent）を理解するには、ES2015のクラスシンタックスをまず理解したほうがいいので、説明します。

## ES2015のクラスシンタックス

犬オブジェクトを生成するクラスを宣言しました。

```js
class Dog {
  constructor() {
    
  }
}
```

これが最小限のクラスの書き方です。

また、コンストラクタ（`constructor()`）は、classによって定義されるオブジェクトの生成時に、初期化を行う特別なメソッドです。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Classes

別で、オブジェクトを生成する際、コンストラクタで引数を1個なり2個なり受け取って、生成されます。

## Reactのstateを持ったクラスで書くReactComponent

基本は同じですが、ES2015のクラスシンタックスと、少し違います。

今回も、犬オブジェクトを生成するクラスを宣言しました。

```js
class Dog extends React.Component{
  constructor(props) {
    super(props)
  }

  render() {
    return  <h1>ワン🐶</h1>;
  }
}
```

`extends React.Component`は、ReactComponentの性質や状態を持ったものを拡張して（`extends`）使う、という意味です。こうすることで、DogクラスはReactComponentの性質を持った状態になれます。

次に、コンストラクタの中身です。

constructorで(props)を受け取って、それをsuper(props)で実行すると言う意味です。

次に、render()。これは必ず持たないといけないそうです。

## DiceAppのReactComponentをつくります

ここまでの話を受けて、DiceAppのReactComponentを作ります。

```js:index.js
import React from "react";
import { render } from "react-dom";

class DiceApp extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return <h1>DiceApp</h1>;
  }
}

render(<DiceApp />, document.getElementById("root"));
```

これでエラーは出なくなりました。

## stateをもたせる

そして、サイコロの目の部分は1〜6で変化していくところなので、その部分にstateを持たせていきます。コンストラクタの中で、`this.state`で変数として宣言します。変数にはオブジェクトで渡さなきゃなので`{}`というシンタックスで渡します。

```js:index.js
import React from "react";
import { render } from "react-dom";

class DiceApp extends React.Component {
  constructor(props) {
    super(props);
    this.state = { num: 1 };
  }

  render() {
    return (
      <div>
        <h1>DiceApp</h1>
        <p>サイコロの目:{this.state.num}</p>
      </div>
    );
  }
}

render(<DiceApp />, document.getElementById("root"));
```

## ボタンを押したら、サイコロの目が変わるようにします

`<p>サイコロの目:{this.state.num}</p>`の下に、`<button>サイコロをふる</button>`をつけましょう。

ボタンをクリックしたら自分自身のメソッドを呼び出すようにします（コールバック）。

```js:index.js
import React from "react";
import { render } from "react-dom";

class DiceApp extends React.Component {
  constructor(props) {
    super(props);
    this.state = { num: 1 };
  }

  render() {
    return (
      <div>
        <h1>DiceApp</h1>
        <p>サイコロの目:{this.state.num}</p>
        <button onClick={this.shakeDice}>サイコロをふる</button>
      </div>
    );
  }

  shakeDice = () => {};
}

render(<DiceApp />, document.getElementById("root"));
```

なにも起こりませんが、一応メソッドも定義しました。アロー関数なのは、JSX部分で使われているメソッド（コールバックしてる）部分`{onClick={this.shakeDice}}`の`this`の先が`shakeDice`メソッドと明示させるためです。他にもいろんな方法はありますが、`create-react-app`の場合はこれが一番らしいです。

クリックされた際に自分自身のstateを変える際、`setState`を使います。


```js:index.js
import React from "react";
import { render } from "react-dom";

class DiceApp extends React.Component {
  constructor(props) {
    super(props);
    this.state = { num: 1 };
  }

  render() {
    return (
      <div>
        <h1>DiceApp</h1>
        <p>サイコロの目:{this.state.num}</p>
        <button onClick={this.shakeDice}>サイコロをふる</button>
      </div>
    );
  }

  shakeDice = () => {
    this.setState({ num: 2 });
  };
}

render(<DiceApp />, document.getElementById("root"));
```

そうすると、ボタンをクリックした際に、1から2に変わります。

ここまでくれば、あとはJSだけの知識でできます。

`Math.random()`に6をかけて乱数の「範囲」を指定して、小数点が出ないように`floor()`メソッドを使って、0が出ないように+1してちょっと調節すれば完了です。

```js:index.js
import React from "react";
import { render } from "react-dom";

class DiceApp extends React.Component {
  constructor(props) {
    super(props);
    this.state = { num: 1 };
  }

  render() {
    return (
      <div>
        <h1>DiceApp</h1>
        <p>サイコロの目:{this.state.num}</p>
        <button onClick={this.shakeDice}>サイコロをふる</button>
      </div>
    );
  }

  shakeDice = () => {
    this.setState({ num: Math.floor(Math.random() * 6) + 1 });
  };
}

render(<DiceApp />, document.getElementById("root"));
```

## コンポーネント部分のファイルを分ける

このままでも機能はするのですが、学びのために、importとexportという、他のファイルから読み込むES2015のシンタックスを利用して、コンポーネント部分と、それを呼び出す部分を分けましょう。

ファイル構成はこんな感じにしましょう。

![スクリーンショット 2018-12-03 00.01.24.png](https://qiita-image-store.s3.amazonaws.com/0/14191/34f1637e-5824-8569-faef-bd3daf04bcc4.png)

まず、新たに作成した`dice-component.js`を見ていきましょう。

```js:dice-component.js
import React from "react";

export class DiceApp extends React.Component {
  constructor(props) {
    super(props);
    this.state = { num: 1 };
  }

  render() {
    return (
      <div>
        <h1>DiceApp</h1>
        <p>サイコロの目:{this.state.num}</p>
        <button onClick={this.shakeDice}>サイコロをふる</button>
      </div>
    );
  }

  shakeDice = () => {
    this.setState({ num: Math.floor(Math.random() * 6) + 1 });
  };
}
```

変わったことといえば

- 別ファイルでもちゃんと`import React from "react";`をしている
    - （Reactのコンポーネントを作っているので）
- `DiceApp`のReactComponentを`export`している

くらいですね。続いて、`index.js`はだいぶスッキリしましたね。

```js:index.js
import React from "react";
import { render } from "react-dom";

import { DiceApp } from "./dice-component";

render(<DiceApp />, document.getElementById("root"));
```

`import { DiceApp } from "./dice-component";`で呼び出した分、だいぶ見た目がスッキリしました。

このように、コンポーネント単位でファイルを分けると、いくつもコンポーネントを作る際は見通しがよくなると思います。

以上です！