🌒

【useEffect】React hookが便利すぎる

6 min read

React hookとは..?

React hookはReact16.8から追加された機能で、クラスコンポーネントでしか使用できなかったstateなどのReactの機能を関数コンポーネントで使用できる機能です。
公式ページは以下です。

https://ja.reactjs.org/docs/hooks-intro.html

React hookのAPIについて紹介していこうと思います。
他のReact hookに関するAPIについても解説していますので、そちらもご覧ください。

useEffectとは...?

useEffect()は副作用を有する可能性のある処理を受け付け、レンダリングが行われたタイミングで実行することができます。言い換えると、レンダリングの後まで、実行タイミングを遅らせることができます。ここで、副作用とは、DOMの更新、変数の更新が挙げられます。

以下のようなクラスコンポーネントにあるライフサイクルメソッドを関数コンポーネントで使用できるイメージです。

  • componentDidMount
  • componentDidUpdate
  • componentWillUnmount

ライフサイクルメソッドについて以下の記事で説明していますので、参考にしてみて下さい。

https://zenn.dev/web_tips/articles/8911d3b761c8f3

使い方

使い方としては主に3パターンあります。

  1. レンダリングされたタイミングで処理を実行する
  2. 初回レンダリング時のみ処理を実行する
  3. 特定のstateの更新による再レンダリングのタイミングで処理を実行する

レンダリングされたタイミングで処理を実行する

  • 第一引数にレンダリングされるタイミングで実行したい関数を指定します。
  • 第二引数には何も指定しません。
  • returnでクリーンアップしたい処理を指定します。(なければreturnブロックは不要)
useEffect(() => {
    console.log('レンダーされました。');
    return () => {
        // clean up処理を記述する。
        console.log('クリーンアップします。');
    };
});

上記のように記述することで、レンダリングされるたびにconsole.log('レンダーされました。');が実行されます。つまり、componentDidMountcomponentDidUpdatecomponentWillUnmountを全指定したようなイメージです。

クリーンアップとは...?

クリーンアップとは、不要となったリソースなどを解放することです。クリーアンアップ処理は以下のような処理が記述されます。

  • イベントリスナーの解除
  • タイマー処理のキャンセル
  • DBアクセス後の接続解放

初回レンダリング時のみ処理を実行する

  • 第一引数にレンダリングされるタイミングで実行したい関数を指定します。
  • 第二引数に[]を指定します。
    • 第二引数は、第一引数に指定した関数を実行を制御する依存データが入ります。
  • returnでクリーンアップしたい処理を指定します。(なければreturnブロックは不要)
useEffect(() => {
    console.log('レンダーされました。');
    return () => {
        // clean up処理を記述する。
        console.log('クリーンアップします。');
    };
}, []);

実際にコードで書いてみました。例として、数字をカウントするカウンターコンポーネントを作ってみました。

Counter2.jsx
// 関数コンポーネントで「useEffect」を使用するためにインポートする。
import React, { useEffect, useState } from 'react';
import '../style.css';

const Counter2 = () => {
    const [counter, setCounter] = useState(0);

    const countUp = () => {
        setCounter(counter + 1);
    };

    const countDown = () => {
        setCounter(counter - 1);
    };

    // useEffectで再レンダーされた場合に実行する処理を記述する。
    useEffect(() => {
        console.log('レンダーされました。');
        document.getElementById('title').innerHTML = `タイトル:${counter}`;
        return () => {
            // clean up処理を記述する。
            console.log('クリーンアップします。');
        };
    }, []);

    return (
        <>
            <h2 id="title">タイトル:初期</h2>
            <div>
                <p>counterは{counter}です。</p>
                <button onClick={countUp}>+1</button>
                <button onClick={countDown}>-1</button>
            </div>
            <div className='line'></div>
        </>
    )
}

export default Counter2
App.jsx
import React from 'react';
import { Counter2 } from './components/index';

function App() {
  return (
    <div>
      <p>useEffectのサンプルです</p>
      <Counter2 />
    </div>
  );
}

export default App;

以下のように動作します。

上記のように記述することで、初回のレンダリング時のみconsole.log('レンダーされました。');が実行されます。つまり、componentDidMountcomponentWillUnmountを記述したようなイメージです。

特定のstateの更新による再レンダリングのタイミングで処理を実行する

  • 第一引数にレンダリングされるタイミングで実行したい関数を指定します。
  • 第二引数に[state]を指定します。
    • 第二引数は、第一引数に指定した関数を実行を制御する依存データが入ります。
  • returnでクリーンアップしたい処理を指定します。(なければreturnブロックは不要)
useEffect(() => {
    console.log('レンダーされました。');
    return () => {
        // clean up処理を記述する。
        console.log('クリーンアップします。');
    };
}, [state]);

上記のように記述することで、特定のstateの更新によってレンダリングされた時のみconsole.log('レンダーされました。');が実行されます。

以下のように、コードを修正しました。

Counter2.jsx
// 関数コンポーネントで「useEffect」を使用するためにインポートする。
import React, { useEffect, useState } from 'react';
import '../style.css';

const Counter2 = () => {
    const [counter, setCounter] = useState(0);

    const countUp = () => {
        setCounter(counter + 1);
    };

    const countDown = () => {
        setCounter(counter - 1);
    };

    // useEffectで再レンダーされた場合に実行する処理を記述する。
    useEffect(() => {
        console.log('レンダーされました。');
        document.getElementById('title').innerHTML = `タイトル:${counter}`;
        return () => {
            // clean up処理を記述する。
            console.log('クリーンアップします。');
        };
    }, [counter]);

    return (
        <>
            <h2 id="title">タイトル:初期</h2>
            <div>
                <p>counterは{counter}です。</p>
                <button onClick={countUp}>+1</button>
                <button onClick={countDown}>-1</button>
            </div>
            <div className='line'></div>
        </>
    )
}

export default Counter2

以下のように動作します。

counterというstateが更新された時の再レンダリング後に、タイトルの表示を更新されます。

まとめ

今回の記事ではuseEffectを紹介しました。次回はuseContextを紹介しようと思います。
githubにサンプルコードを載せていますので、気になった方はご覧ください。

https://github.com/Tomoki-webpro/react-hooks-study

参考記事

https://ja.reactjs.org/docs/hooks-reference.html#usestate

https://qiita.com/seira/items/e62890f11e91f6b9653f

Discussion

ログインするとコメントできます