LoginSignup
5
4

More than 3 years have passed since last update.

ReactのuserEffectでsetIntervalした時の、インターバルが無限に定義される問題に対処する

Posted at

はじめに

React上でsetIntervalを使うとき、そのsetIntervalの処理が副作用を生む場合、無限ループに陥ることがあります。
本稿では、その対処法について紹介します。

環境/前提

<LABEL>-<MESSAGE> <LABEL>-<MESSAGE>

  • 上記ライブラリがインストールされていること。

使用ブラウザ:Chrome

実装

無限ループに陥るコード

    React.useEffect(() => {
        // インターバルを作成
        window.setInterval(() => {
          hasSideEffectFunction();
        }, 5000);
    }, [someState]);

上記のコードでは、hasSideEffectFunction()が副作用を引き起こし、実行されるたびにレンダーされます。

さらにレンダーされる度に、setInterval()が実行され、インターバルが無限に増えていきます。

解決策

    // インターバルIDを保持する為のref変数(レンダーされても値を保持する)
    const intervalNo = React.useRef(0);

        React.useEffect(() => {
           // インターバルが作成されていない時のみ、setInterval()する
           if (intervalNo.current == 0) {
              // インターバルを作成
              intervalNo.current = window.setInterval(() => {
                 hasSideEffectFunction();
              }, 5000);
           }
        }, [someState]);

上記のように、setInterval()の返り値を、useRefを使って保持することで、レンダーされるたびにインターバルが作成されるのを防ぐことができます。

これでレンダーを通してインターバルを1つに保つことはできました。
しかし、画面遷移などのコンポーネントの呼び出しをされると、useRefが再び0に定義され、インターバルが作成されてしまいます。

 for (let i = 1; i < 1000; i++) window.clearInterval(i);

その対策として、setInterval()を実行する前に、上記のコードにより、定義されているであろうインターバルをfor分で回して削除するようにしてます。
これで画面遷移を通してもインターバルを1つに保つことができます。

(正直無理やり対応してる感が否めないので、定義済みのインターバルを取得できるような知見がある方がいたら教えてほしいです。。。)

5
4
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4