【React】 useEffectで描画後に処理を実行

useEffectを用いると、そのコンポーネントがレンダリングされた後に実行したいコードを書くことができます。副作用フックと呼ばれます。

useEffectしなかったときのよくある失敗

学び始めたばかりの頃によくあるのが、一度だけ実行したいものとして、普通に処理を書くパターンです。

export default function App() {
    const [x, setX] = useState(10);
    
    const addValue = () => {
        setX(x + 5);
    };

    // 一度だけ実行したい処理
    const hoge = "...";
    // ...
    
    return (
        // ...
    );
}

しかし、これではうまくいきません。コンポーネントの関数は、useしている値が更新されるなどが起こると、関数全体を実行し直すためです。全体が実行し直されるので、上のような書き方をするとその度に何度も実行されるということになってしまいます。

useEffectの実行のタイミング

useEffectに入れた処理は、レンダリング後とアンマウント後(指定したときのみ)に実行されます。つまり

export default function App() {
    const [x, setX] = useState(10);
  
    // 初回と、xを更新してレンダリングされた後に実行
    const addValue = () => {
      setX(x + 5);
    };
  
    return (
      <div>
        <p>{x}</p>
        <button onClick={addValue}>addValue</button>
      </div>
    );
}

returnまで終わり、更に描画も完了した後に実行される、ということになります。useしている値を更新するなどした際にもレンダリングされるため、その度にuseEffectに入れた関数が実行されます。

レンダリングが終わった後なので、DOMが更新済みの状態で処理が実行されます。

useEffectを使う

宣言

useEffectには、レンダリング後に実行したい関数を入れます。

import { useEffect, useState } from 'react';

export default function App() {
    const [x, setX] = useState(10);
  
    const addValue = () => {
        setX(x + 5);
    };

    // 初回レンダリング後と、useした値の更新後に自動で実行
    useEffect(() => {
        // レンダリング後なので、xは更新後の値
        document.title = `App | ${x}`;
    });
  
    return (
        // ...
    );
}

特定の値が変わったときだけ処理

上のコード例では、もしほかにも変化する値があった場合に、関係ない値が変化してもレンダ後に実行されます。しかし、上の例ではx以外が変化しても再実行する必要はないはずです。

そこで、useEffectの第2引数に監視する変数を配列で入れます。そうすると監視している変数が変化したときのみ実行されるようになります。

// 最初と、レンダリング後にxが変わっていた時だけ実行
useEffect(() => {
    document.title = `App | ${x}`;
}, [x]);

マウント時だけ処理する

もし最初の1回だけ実行したいものを作る場合、監視対象を空の配列にすることで、マウント時以外実行しないようにします。

// [] なので、何が変化しても再実行しない
useEffect(() => {
    document.title = `App | Home`;
}, []);

無限ループに注意

もしuseEffect内で監視対象の値を変更した場合、その変更がトリガーとなってまた実行されます。

useEffect(() => {
    setX(x + 1);
}, [x]);

この例では、xを監視対象にしていますが、

  1. xが更新される
  2. useEffectに入れた関数が実行される
  3. その中でxが更新される
  4. これによってuseEffectに入れた関数が実行される

のようにして無限ループします。この例では対象を指定しているので分かりやすいですが、

useEffect(() => {
    setX(x + 1);
});

のように第2引数を省略した場合は全てが監視対象となるため、無限ループしやすくなり、注意が必要です。

クリーンアップ

そのコンポーネントが消えるとき (アンマウントされるとき) に、どのような後処理を行うかを書くことができます。

クリーンアップ用のコードは、useEffectに入れる関数の戻り値に関数として設定します。

export default function Counter() {
    const [x, setX] = useState(10);
    
    const addValue = () => {
        setX(x + 5);
    };

    useEffect(() => {
        document.title = `App | ${x}`;

        return () => {
            document.title = "App";
        }
    }, [x]);

    return (
        // ...
    );
}

このコードでは、xの値が変わるごとにタイトルを更新し、このコンポーネントがアンマウントされたらタイトルをAppに戻す、という処理をしています。

クリーンアップが無ければ、アンマウントしても何も起こりません。

まとめ

useEffectは、マウント時、監視している値の更新時、アンマウント時の3つのタイミングで呼び出されます。マウント時だけ呼びたい場合は、監視対象を無しにすれば実現できるということを覚えておきましょう。

react useeffect thumb

役に立ったらシェアしよう!