Reactについて一年ぶりにまとめてみた

## はじめに

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/924294/d6471fce-7957-a350-7374-64521fab2bba.png" width=50%  />

一年前にReactを使用してアプリ作成や学習を行い転職活動をしていたが、当時の僕はプログラミングやアプリケーションは動けばいいくらいのトンチンカンでまともにドキュメント読み込む力もありませんでした。
そして現在、エンジニア一年生として改めてReactの中で気になっている**クラスコンポーネントと関数コンポーネントの違い**や**ライフサイクル**、**状態管理**、**React Hooks**などといったReact基礎について理解したく今回まとめてみました。

## クラスコンポーネントと関数コンポーネントの違い

まず結論から言うと**propsやstate、ライフサイクルの記述方法が違う点**がありました。
（React Hooksが登場してからです。※*React 16.8.0版リリース：2019/2/6*）

まず軽く前提としてUIを構築するのに**コンポーネント**という概念と、親から子コンポーネント間でデータを渡す**props**という概念があります。
詳しくはドキュメントの[コンポーネントとprops](https://ja.reactjs.org/docs/components-and-props.html)に記載してあります。

そしてコンポーネントを作成する際には、

- クラスコンポーネント
- 関数コンポーネント

の二つが存在します。

先程の**propsやstate、ライフサイクルの記述方法が違う点**は、クラスコンポーネントでしか行えなかったstateやライフサイクル機能がReact Hooksが登場して以来、関数コンポーネントでの使用が**可能**になりました。
それまで関数コンポーネントの役割としてはViewを表示するための役割で、ステート管理している親コンポーネントから**props**としてデータを受け取るステートレスとしてのコンポーネントでした。

実際にコード別で簡単にクラスコンポーネントと関数コンポーネントを比較してみました。

####クラスコンポーネント

```javascript
import React from "react";

class ClassComponent extends React.Component {
 render() {
   return <h1>Hello, world</h1>;
 }
}
```
クラスコンポーネントを作成するのに、`React.Component`を継承し必ず`render()`を定義する必要があります。
`render()`については、ライフサイクルの箇所で説明します。

####関数コンポーネント

```javascript
import React from "react";

function FunctionalComponent() {
 return <h1>Hello, world</h1>;
}
```
関数コンポーネントに関しては、関数の中でJSXを記述することでコンポーネントの作成ができます。

## state（状態）管理

コンポーネントを利用する時に設定できる**State**という値があります。
Reactのstateや状態管理としては、主に**Redux**, **useState**, **useContext**など様々なやり方があります。

### useState
useStateは、関数コンポーネントでのstate管理・更新をすることができます。
`const [値,  更新する値] = useState(初期値)`
として扱うことができます。

useStateを使用して**親コンポーネントで値（state）**をもち、**子コンポーネントでprops**で値を受け取るといった伝達が鉄板ですね。

しかし、規模が大きくなるにつれてコンポーネントツリーの階層が多くなり**props**のバケツリレーの連続で管理のメンテナンスやパフォーマンスが疎かになります。
そういった時に役立つのが、先程説明した**Redux**や次の**useContext**を使用することでstate管理を円滑にすることができます。

### useContext

コンポーネントツリー内にpropsを経由せずとも値を渡すやり方がコンテキストと呼ばれる方法があります。主に多くのコンポーネントで扱う値をグローバルステート管理したい時に使用します。
注意したいのが、管理しているコンテキストの値の変や（コンテキストを設定した）コンポーネントがレンダリングすると渡したコンテキスト値も変更するので出来るだけシンプルな管理が必要になります。
useContextを使用する場合は以下が必要です。

- `createContext()` オブジェクトのデフォルト値を引数に設定。
- `Provider` providerで包みvalue値を決めることでコンテキストを設定します。
- `useContext()` 引数にコンテキストを渡すことで使用可能。

```javascript
const themes = {
  light: {
    background: "#eeeeee"
  },
  dark: {
    background: "#222222"
  }
};
// コンテキストオブジェクトの設定
const ThemeContext = React.createContext(themes.light);

// 親コンポーネント
function App() {
  return (
      // Providerでコンポーネントを包み、valueの値を決めて設定 
    <ThemeContext.Provider value={themes.dark}>
      <Toolbar />
    </ThemeContext.Provider>
  );
}
// 子コンポーネント
function Toolbar() {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

// 子孫コンポーネント
function ThemedButton() {
   // useContextの引数にコンテキストオブジェクトを設定することで使用可能。
  const theme = useContext(ThemeContext);
  return (
    <button style={{ background: theme.background }}>
      I am styled by theme context!
    </button>
  );

```
#### クラスコンポーネントの場合は、
ちなみに**クラスコンポーネント**では`constructor`内で、`state`の管理を行い、`setState()`でstateを更新することができます。
詳しくは、[コンポーネントのstate](https://ja.reactjs.org/docs/faq-state.html)に記載してあります。


### Redux

状態管理ライブラリと呼ばれており、本来￥コンポーネントでのstate管理を行いますがReduxでは**Store**を使用しコンポーネントを切り離してstate管理を行います。扱うデータが多い中規模・大規模での使用に特化しております。

reduxの内容をとてもわかりやすくまとめた記事がありました。
https://qiita.com/kitagawamac/items/49a1f03445b19cf407b7

### まだまだやり方たくさんある。。。

主に３つの状態管理を挙げましたが他にもReact Hooksの**useReducer**、GrahpQL利用時には**Apollo Client**を使用するケースや状態管理ライブラリであるreduxと類似した**Recole**や**MobX**など、Reactには様々やり方があってサービスの規模感に応じて技術選定が必要になるので一年ぶりに凄みを感じました。

## ライフサイクルとは

まず簡単にライフサイクルとは、**コンポーネントが生まれてから死ぬまでをサイクルとするように、
生成（Mounting）➡︎ 更新（Updating）➡︎ 削除（Unmounting）の繰り返すこと**を言います。

公式ドキュメントでは、以下のライフサイクル図が見れます。
![スクリーンショット 2022-01-23 21.39.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/924294/8a3e502a-35e3-9793-deac-dbb2fb40eec2.png)

主に使用されているライフサイクルメソッドは、以下になります。

📌 **Mounting**

- `constructor()` マウントされる前に呼び出されるメソッドで、ローカルstateの初期化やイベントのバインドを行う。
- `render()` 仮想DOMを構築するメソッド。もちろんコンポーネントに必須でもある。
- `componentDidMount()` 最初の`render()`が呼びだされる（マウント直後）メソッドで、ネットワークの通信処理に利用されることがある。

📌 **Updating**

- `render()`上記の内容と同じ。
- `componentDidUpdate()` 更新が完了したタイミングのメソッド。更新完了後のネットワークリクエストの通信時に利用する。

📌 **Unmounting**

- `componentWillUnmount()` コンポーネントが破棄されるタイミング（アンマウント）のメソッド。ネットワークリクエストのキャンセルや作成したデータの加工（削除）に使用。

以上で説明したライフサイクルメソッドは、クラスコンポーネントでの使用になります。

ちなみに関数コンポーネントの場合はReact Hooksの`useEffect`を使用して、ライフサイクルを行うことができます。

### React Hooks useEffect版のライフサイクル

React Hooksの**useEffect**は、先程の上記で紹介したライフサイクルメソッドである`componentDidMount()`, `componentDidUpdate()`, `componentWillUnmount()`を一つにまとめたメソッドです。
なので、useEfftctを使用することでライフサイクルを作成することができます。

#### useEfftctの使い方

`useEffect(第一引数：()=> { 処理 }, 第二引数：[依存変数])`として記述します。

- 第一引数のコールバック関数はレンダリング時に呼ばれ副作用の処理を行います。また、その処理の中で戻り値を関数としたもの**クリーンアップ関数**と呼ばれてコンポーネントがアンマウントされた時に実行されます。
- 第二引数は、省略することもできます。配列の中身に依存させる変数を格納することで、変数が変更された場合に実行される仕組みになっております。

※ここでいう**副作用**とはレンダリング時に関係のない処理のことを指しております。

```javascript
import React, { useEffect, useState } from "react";

const Example = () => {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const id = setInterval(() => {
      console.log(count);
    }, 2000);

    // クリーンアップ関数
    return () => {
      clearInterval(id);
    };
  }, [count]); // countが依存変数

  return <button onClick={() => setCount(count + 1)}>Click me</button>;
};

export default Example;
```
上記の内容は、レンダリング時に`count`の値がコンソールログに2秒後に表示➡︎`count`がプラスされるボタンをクリックすると再レンダリングされ2秒後にcountがプラスされているコンソールログが表示といった流れです。そして、コンポーネント破棄（アンマウント）されたら`count`を解除するといったクリーンアップ関数が実行されます。

#まとめ

- Reactのコンポーネント作成は、**クラスコンポーネント**と**関数コンポーネント**の概念がありstateやライフサイクルの記述がそれぞれある。
- state管理においては、useState, useContextなどのHooksやReduxなど様々あり規模感に応じて使い分ける。
- ライフサイクルは**Mounting ➡︎ Updating ➡︎ Unmounting**のサイクル。