Reactを学ぶXI〜React Hooksその2〜

## ■ はじめに

タイトルについて記事にしました。
この記事で得る内容は以下の通りです。

・ Reactの基礎知識が増える
・ React Hooks 関数コンポーネントでもライフサイクルを扱う方法について

## ■ useEffect()メソッド

React Hooksでライフサイクルを作る時は、<font color="red">useEffect()メソッド</font>を使います

#### ・ useEffect()メソッドを使うメリット

・ Functional Componentで書くことができるので、記述量が減らせる
→ Class Componentと比べてソースコードがシンプルで見やすいので、書きやすさと保守性が上がる

・ コードを分かりやすくまとめることができる
→ useEffectメソッドの中で、機能毎にコードをまとめる事ができるので、コードの可視性が上がる

#### ・ useEffect()の仕組み

useEffectメソッドの中に記述した処理は、レンダー毎に走ります
代替できるメソッドは、<font color="green">componentDidMount()</font>、<font color="blue">componentDidUpdate()</font>、<font color="red">componentWillUnmount()</font>です

#### ・ useEffect()の使い方

いくつかパターンがありますので、パターン毎に説明します

```react:パターン①：レンダー毎

// レンダー毎に処理が走る基本の型で、useEffect()内にCallback関数() => {}を書く

useEffect(() => {
    console.log('render!') // Callbackはレンダー毎に呼ばれる
    return () => {
        console.log('Unmounting!')  // returnするCallback関数はアンマウント時に呼ばれる（クリーンアップ関数）
    }
})
```

```react:パターン②：マウント時のみ

// Class Commponentでは、componentDidMount()に書いていた処理を実行するパターン

useEffect(() => {
    console.log('render!')
}, [])  // useEffectメソッドの第二引数に空の配列を渡すと、最初の1回（マウント時）のみ処理が実行される

// 第二引数の配列の値を、前回レンダーと今回レンダーで比較し、変更があればCallback関数を実行する
```

```react:パターン③：マウント&アンマウント

// ①と②の複合型で、マウント時及び、アンマウント時のみ実行する

useEffect(() => {
    console.log('render!')  // 通常のCallbackはマウント時のみ
    return () => {
        console.log('Unmounting!') // アンマウント時はreturn内のクリーンアップ関数が実行される
    }
},  []) // updating期間は配列の中身は空なので実行しない
```

```react:パターン④：特定のレンダー時に関数を実行

// useStateメソッドと使われることが多い

const [limit, release] = useState(true); // limitというstateの初期値がtrueで、releaseという関数でlimitを変更する事ができる

useEffect(() => {
    console.log('render!') // limitの値が変わると処理が実行される
}, [limit]) // useEffectメソッドの第二引数の配列にlimitを指定し、前回のレンダーと今回のレンダーで値を比較して変わった時にCallback関数が呼ばれる
```

## ■ 例

前回は、Articleメソッドの中でuseStateを使って、公開状態の切り替えをしていました

```react:Article.jsx
import React, { useState } from "React";
import LikeButton from "./LikeButton";

const Article = (props) => {
  const [isPublished, togglePublished] = useState(false);

  return (
    <div>
      <h2>{props.title}</h2>
      <label htmlFor="check">公開状態：</label>
      <input type="checkbox" checked={isPublished} id="check" onClick={() => togglePublished(!isPublished)} />
      {<LikeButton/>}
    </div>
  );
};

export default Article;
```

そして、Blog.jsxでライフサイクルを使った処理を、useEffectを使って代替します

```react:LikeButton.jsx
import React, { useState, useEffect } from "React"; // useStateとuseEffectを宣言

const LikeButton = () => {
    count [count,counter] = useState(0); // useStateを使って、カウント用のstate（countというstateと、counter(変更用のメソッド)）を作ります

    const countUp = () => {
        counter(count +1); // 上記のcounterメソッドを使って、countの値に+1して返す処理
    };

    useEffect(() => {
        document.getElementById("counter").addEventListener("click", countUp);  // counterというidを持つDOM要素にクリックした時、countUp変数を呼び出す
    }):

    return (
        <button id={"counter"}>いいね数： {count}</button> // いいね数はcountのstateを表示するようにします
    ) 
};
```

この状態で、カウントアップされているのが確認できます

![カウントされる.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/772631/7e36d4d9-7cdf-323f-1472-6a7702c2b12b.gif)

<font color="red">componentWillUnmount()</font>の部分も実装していきます

```react:LikeButton.jsx
// 中略

    useEffect(() => {
        document.getElementById("counter").addEventListener("click", countUp);
        return() => {document.getElementById("counter"}.removeEventListener("click", countUp); // componentWillUnmountの処理で、いいねボタンはマウントされた時にイベントが設定されて、アンマウントされる時は、イベントリスナーが解除される
    }):

// 中略
```

続けて残りの<font color="blue">componentDidUpdate()</font>も実装します

```react:LikeButton.jsx
// 中略

    useEffect(() => {
        document.getElementById("counter").addEventListener("click", countUp);
        if (count >= 10) {
            counter(0) // componentDidUpdateの部分は、useEffectメソッドが毎回呼ばれるので、条件を書くだけでOKです
        }
        return() => {document.getElementById("counter"}.removeEventListener("click", countUp);
    }):

// 中略
```

これでuseEffectメソッドを使っての実装ができました

![useeffectでライフサイクル.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/772631/88e9969b-f868-b6ba-ba40-c1480ca51755.gif)