Reactコンポーネント基礎

## 説明したいこと
- Reactのコンポーネントとは
- コンポーネントの種類
- コンポーネントの使い分け
- 単純なコンポーネントの作成方法

## Reactとは
Facebookが開発したコンポーネント指向のUI構築ライブラリです。 

[React公式サイト](https://ja.reactjs.org/)

## コンポーネントとは
Reactはコンポーネントと呼ばれるUIの部品を組み合わせてアプリを構築していきます。コンポーネントは値を受け取ることができ、受け取った値により見た目、動きを変えます。
適度な粒度で独立したコンポーネントを作成していくことで、アプリ内の様々な箇所で使い回す事ができ、見やすいコードになると思います。

Reactでアプリを開発する際はこの、コンポーネントを　作っていくことが大半の作業になるかと思います。

Reactのコンポーネントには大きく分けて以下の2つの作り方があります。

- クラスコンポーネント (クラスでコンポーネントを定義)
- 関数コンポーネント (関数でコンポーネントを定義)

ですが、今からReactを始める場合は関数コンポーネントでの作り方だけ分かっていれば問題ないです。
というのも、以前までClass Componentでしかできないことがあったのですが、Hooksと呼ばれるものの登場により、できることに差がなくなったからです。
この記事の中では、関数コンポーネントのみを対象に説明していきます。

## コンポーネントの作り方

### 用語
- Props : コンポーネントに渡されるパラメータ
- State : コンポーネントが持つ状態
- JSX : コンポーネントのUIの記述をする

### コンポーネントの種類
Reactのコンポーネントには以下の2種類があります

- Presentational Component
- Container Component

Presentational Componentは見た目の定義だけをし、JSXを多く持ちます。
Container Componentはコンポーネントのロジックを定義します。
これらは、もともとはReduxと呼ばれるReactの状態管理を行うライブラリで用いられていたものですが、Reduxを使用していなくてもコンポーネントを見た目とロジックで分けることでコードが見やすく、管理もしやすくなると感じています。

呼び方としてははPresentational Componentをコンポーネント、Container Componentはコンテナと呼ぶことが多い気がします。

## コンポーネントを作成してみる

今からこんな感じの、押した回数によってカウントが増えていくコンポーネントを例として作成します。
![ezgif.com-gif-maker.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598845/3fd88d1c-d439-30a8-1274-d8f5a4e8ffce.gif)

### 環境の構築
この記事では割愛させてもらいます🙇‍♂️
基本的には`create-react-app`で作成されたプロジェクトでTypeScriptを使用していくことを想定してます。

### Presentational Componentの作成
コンポーネントを作成する際はまず、見た目を作成していきます。
ここでは、ボタンとクリック回数を表示するラベルという、`good`と`bad`で共通した部品を作ります。

```RateButton.tsx
import React, { FC } from "react";

// コンポーネントのProps(パラメータ)の型を定義
type RateButtonProps = {
  buttonText: string;
  clickedNumber: number;
  onClick: () => void;
};

// 関数コンポーネント
export const RateButton: FC<RateButtonProps> = (props) => {
  const { buttonText, clickedNumber, onClick } = props;

  return (
    <>
      <button onClick={onClick}>{buttonText}</button>
      <label>　{clickedNumber}</label>
    </>
  );
};
```

このファイルを作成するだけでは画面上に表示されないので一時的に、`App.tsx`をこんな感じにします。


```App.tsx
import "./styles.css";
import { RateButton } from "./RateButton";

export default function App() {
  return (
    <>
      {/* とりあえず表示するために固定を渡している */}
      <RateButton buttonText='good👍'　clickedNumber={0} onClick={() => console.log('clicked')} />
    </>
  );
}
```
※`index.tsx`が`App.tsx`を読み込んで、その内容を表示する流れになっているのですが、細かい箇所は省略します。

そうすると、以下のコンポーネントが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598845/a30fb2d1-ec4d-be17-d27d-870746b85f3f.png)

### Container Componentの作成
今のままだと、クリックしても何も反応しないものになってしまうので
コンテナを使用してロジックを書いていきます。

```BadButtonContainer.tsx
import React, { FC, useState } from "react";
import { RateButton } from "./RateButton";

type BadButtonContainerProps = {
  buttonText: string;
};

export const BadButtonContainer: FC<BadButtonContainerProps> = (props) => {
  // コンポーネントが持つ　State(状態)
  const [badNumber, setBadNumber] = useState<number>(0);

  const addBadNumber = () => {
    setBadNumber((preState) => preState + 1);
  };

  return (
    <RateButton {...props} clickedNumber={badNumber} onClick={addBadNumber} />
  );
};
```

コード上で出てきている`useState()`に関してですが、これは関数コンポーネントでState(状態)を保持できるようにした機能です。今回はクリックしたという動作に合わせてStateが変化していくのでコンテナにStateを持たせています。

[useState](https://ja.reactjs.org/docs/hooks-reference.html#basic-hooks)

これでBadボタンの動きまで作成できました。Goodボタンもベースとなる`RateButton`は同じでStateの動きが異なるだけなので同様に作成します。

```GoodButtonContainer.tsx
import React, { FC, useState } from "react";
import { RateButton } from "./RateButton";

type GoodButtonContainerProps = {
  buttonText: string;
};

export const GoodButtonContainer: FC<GoodButtonContainerProps> = (props) => {
  const [goodNumber, setGoodNumber] = useState<number>(0);

  const addGoodNumber = () => {
    setGoodNumber((preState) => preState + 1);
  };

  return (
    <RateButton {...props} clickedNumber={goodNumber} onClick={addGoodNumber} />
  );
};
```

あとは`App.tsx`を以下のように修正します。

```App.tsx
import React from 'react';
import { BadButtonContainer } from "./BadButtonContainer";
import { GoodButtonContainer } from "./GoodButtonContainer";

export default function App() {
  return (
    <>
      <GoodButtonContainer buttonText="good👍" />
      <BadButtonContainer buttonText="bad👎" />
    </>
  );
}
```

これで完成です。

## まとめ
この記事ではコンポーネントのみを対象に説明しました。