State を使った React コンポーネントを利用したアプリ開発（React基礎講座7）

# はじめに

今回は、前回学んだ`State`を使った`React`コンポーネントを利用して、ちょっとしたアプリケーションを作りたいと思います。

# シリーズ

本記事はReact基礎講座のための連載になっています。気になる方のために、前の章は以下です。

[State を使った React コンポーネント（React基礎講座6） \- Qiita](https://qiita.com/ryosuketter/items/d5d1bae026c10f2c988e)

最初の記事は、以下です。

[Reactを使ってJSXの内容をレンダリングする（create\-react\-app）（React基礎講座1） \- Qiita](https://qiita.com/ryosuketter/items/dbac89f398787a1a73d4)

# テストの出来栄えを判定するちょっとしたアプリケーション

今回作成する、ちょっとしたアプリケーションの内容を説明します。

例えば、学校の100満点のテストを受けた時に

- 100だった場合
- 80点以上だった場合
- 50点以上だった場合
- それ以下だった場合

に、viewが変わるような仕掛けを、State を使った React コンポーネントを利用して作成していきましょう。

# Reactアプリを作成する際の採用構成ファイル

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

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

次に、React.Componentを作成していきましょう。

主に必要な記述は

- extends
- constructor
- render

でしたね。では、クラス名はテストなので、`exam`として書いていきましょう。

今回はテストの点数をstateにしてください。名前は`score`（初期値: 10）とでもしていきましょう。

すると、こんな感じにかけると思います。

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

class Exam extends React.Component {
  constructor(props) {
    super(props);
    this.state = { score: 10 };
  }
  render() {
    return <h1>{this.state.score}</h1>;
  }
}

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

viewには`10`とだけ、表示されたと思います。

では、次に、温度変化をコントロールするボタンを作っていきます。

主な手順は

- `+`ボタンと`-`ボタンのjsxを作成してください
- 上記のボタンから、stateを変更するようなメソッドをアロー関数で作成してください
    - メソッド名
        - 1+する方は `onPlusBtnClick()` 
        - 1-する方は `onMinusBtnClick()` 

以下が、正解（書き方はいくらでもありますが...）。

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

class Exam extends React.Component {
  constructor(props) {
    super(props);
    this.state = { score: 10 };
  }

  render() {
    return (
      <div>
        <h1>{this.state.score}</h1>
        <button onClick={this.onPlusBtnClick}>+</button>
        <button onClick={this.onMinusBtnClick}>-</button>
      </div>
    );
  }

  onPlusBtnClick = () => {
    this.setState({ score: this.state.score + 1 });
  };
  onMinusBtnClick = () => {
    this.setState({ score: this.state.score - 1 });
  };
}

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

こんな感じですね。

同じような要領で、+10、そして、-10になるようなJSXとメソッドも作って見ましょう。

以下が、正解（書き方はいくらでもありますが...）。

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

class Exam extends React.Component {
  constructor(props) {
    super(props);
    this.state = { score: 10 };
  }

  render() {
    return (
      <div>
        <h1>{this.state.score}点</h1>
        <button onClick={this.onPlusBtnClick}>+</button>
        <button onClick={this.onMinusBtnClick}>-</button>
        <button onClick={this.onPlusBtnTenClick}>+10</button>
        <button onClick={this.onMinusBtnTenClick}>-10</button>
      </div>
    );
  }

  onPlusBtnClick = () => {
    this.setState({ score: this.state.score + 1 });
  };
  onMinusBtnClick = () => {
    this.setState({ score: this.state.score - 1 });
  };
  onPlusBtnTenClick = () => {
    this.setState({ score: this.state.score + 10 });
  };
  onMinusBtnTenClick = () => {
    this.setState({ score: this.state.score - 10 });
  };
}

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

```

こんな感じですね。

## テストの出来栄えを判定する条件を追加する

学校の100満点のテストを受けた時に

- 100だった場合: 天才
- 80点以上だった場合: 秀才
- それ以下だった場合: 伸び代あり！

という評価を点数に合わせて動的に表示が変わるように作成しましょう。

手順としては

- 上の条件で文字列を返すようなメソッドをアロー関数で作成する
    - メソッド名は `evaluationScore`
- そのメソッドを受け取るJSXを`h1`以下に用意する

以下が、正解（書き方はいくらでもありますが...）。

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

class Exam extends React.Component {
  constructor(props) {
    super(props);
    this.state = { score: 10 };
  }

  render() {
    return (
      <div>
        <h1>{this.state.score}点</h1>
        <p>評価:{this.evaluationScore(this.state.score)}</p>
        <button onClick={this.onPlusBtnClick}>+</button>
        <button onClick={this.onMinusBtnClick}>-</button>
        <button onClick={this.onPlusBtnTenClick}>+10</button>
        <button onClick={this.onMinusBtnTenClick}>-10</button>
      </div>
    );
  }

  onPlusBtnClick = () => {
    this.setState({ score: this.state.score + 1 });
  };
  onMinusBtnClick = () => {
    this.setState({ score: this.state.score - 1 });
  };
  onPlusBtnTenClick = () => {
    this.setState({ score: this.state.score + 10 });
  };
  onMinusBtnTenClick = () => {
    this.setState({ score: this.state.score - 10 });
  };

  evaluationScore = score => {
    if (score >= 100) {
      return "天才";
    } else if (score >= 80) {
      return "秀才";
    } else {
      return "伸び代あり！";
    }
  };
}

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

こんな感じですね。

## テストの出来栄えを判定してCSSのスタイリングも変化するように条件を追加する

今度は、`state`（テストの点数）の値に伴ってCSSが変化するような変更を加えていきましょう。

手順としては以下のような感じ

- `h1`タグに`className`（Reactでスタイリングする場合の書き方）を指定して、関数`evaluationScore`に引数`this.state.score`を渡して、そこから帰る文字列をクラス名として利用する
- `style.css` にスタイルを書いて、`index.js`でそれを`import`する
- cssと`index.js`は同じ階層
- 関数（`evaluationScore`）が返す文字列も日本語から英語にします

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

class Exam extends React.Component {
  constructor(props) {
    super(props);
    this.state = { score: 10 };
  }

  render() {
    return (
      <div>
        <h1 className={this.evaluationScore(this.state.score)}>
          {this.state.score}点
        </h1>
        <p>評価:{this.evaluationScore(this.state.score)}</p>
        <button onClick={this.onPlusBtnClick}>+</button>
        <button onClick={this.onMinusBtnClick}>-</button>
        <button onClick={this.onPlusBtnTenClick}>+10</button>
        <button onClick={this.onMinusBtnTenClick}>-10</button>
      </div>
    );
  }

  onPlusBtnClick = () => {
    this.setState({ score: this.state.score + 1 });
  };
  onMinusBtnClick = () => {
    this.setState({ score: this.state.score - 1 });
  };
  onPlusBtnTenClick = () => {
    this.setState({ score: this.state.score + 10 });
  };
  onMinusBtnTenClick = () => {
    this.setState({ score: this.state.score - 10 });
  };

  evaluationScore = score => {
    if (score >= 100) {
      return "genius";
    } else if (score >= 80) {
      return "excellence";
    } else {
      return "potential";
    }
  };
}

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

```css:style.css
/* 青 */
.genius {
  color: #2f00ff;
}
/* 緑 */
.excellence {
  color: #00ff0d;
}
/* 赤 */
.potential {
  color: #ff0000;
}
```

![0595284e09dae1e06e23e80653de890d.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14191/7a230662-de11-410f-f105-d698d0844e45.gif)

こんな感じですね。

## リファクタ

多少、冗長な書き方があるので、短く書いていきましょう。

`{}`で必要なものを取り出します。

例えば、この記述 `this.state.score`

```js
const { score } = this.state
```

これは、`state`の中に、`score`があれば、constで定義した`score`に入れる。という意味です。こうかけば、いちいち `this.state.score` 書かなくても、`score` だけで済みます。

renderメソッドの中と、その下の`setState`する関数の中で `const { score } = this.state;`を書いています。

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

class Exam extends React.Component {
  constructor(props) {
    super(props);
    this.state = { score: 10 };
  }

  render() {
    const { score } = this.state;
    return (
      <div>
        <h1 className={this.evaluationScore(score)}>
          {score}点
        </h1>
        <p>評価:{this.evaluationScore(score)}</p>
        <button onClick={this.onPlusBtnClick}>+</button>
        <button onClick={this.onMinusBtnClick}>-</button>
        <button onClick={this.onPlusBtnTenClick}>+10</button>
        <button onClick={this.onMinusBtnTenClick}>-10</button>
      </div>
    );
  }

  onPlusBtnClick = () => {
    const { score } = this.state;
    this.setState({ score: score + 1 });
  };
  onMinusBtnClick = () => {
    const { score } = this.state;
    this.setState({ score: score - 1 });
  };
  onPlusBtnTenClick = () => {
    const { score } = this.state;
    this.setState({ score: score + 10 });
  };
  onMinusBtnTenClick = () => {
    const { score } = this.state;
    this.setState({ score: score - 10 });
  };

  evaluationScore = score => {
    if (score >= 100) {
      return "genius";
    } else if (score >= 80) {
      return "excellence";
    } else {
      return "potential";
    }
  };
}

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

これで、冗長な書き方が多少なくなったかと思います。

以上です。参考にしてみてください。

# 参考

- 改訂新版JavaScript本格入門 ~モダンスタイルによる基礎から現場での応用まで | 山田 祥寛