React Can’t perform a React state update on an unmounted component. が出た時に確認すること

ポーリング処理などを行っている時に遭遇する「Can’t perform a React state update on an unmounted component.」の対処方法についてです。

このエラーは、アンマウントされたコンポーネントのstateに対して更新を行おうとした際に発生します。

コンポーネント内でsetIntervalなどを使って、stateに更新をかけている場合などです。

例を見てみます。

以下は親ページです。liタグをクリックすると、HogeコンポーネントとPage2という文字列を切り替えています。

import Hoge from "./Hoge";
import {useState} from "react";

const App = () => {
  const [page, setPage] = useState(1);

  return (
    <div>
      <ul>
        <li onClick={() => setPage(1)}>page1</li>
        <li onClick={() => setPage(2)}>page2</li>
      </ul>
      {page === 1 ? <Hoge/> : 'Page2'}
    </div>
  );
};

export default App;

問題のコンポーネントです。

import {useEffect, useState} from "react";

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

  useEffect(() => {
    setInterval(() => {
      setCount(c => c + 1);
    }, 1000);
  }, []);

  return (
    <div>
      <h2>Hoge</h2>
      <div>{count}</div>
    </div>
  );
};

export default Hoge;

stateとしてcountという値を持っています。

そして、useEffect内で1秒ごとにcountをインクリメントする処理をしています。

ここで問題となるのは、Hogeコンポーネントがアンマウントされても、setIntervalが実行され続けるところです。

そうすると、countに対して更新をかけ続けようとするのですが、countはHogeがアンマウントされたことによって消えているので、今回のエラーが起きます。

以下のように、コンポーネントのアンマウント時にclearIntervalしてあげればエラーが解消します。

import {useEffect, useState} from "react";

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

  useEffect(() => {
    const timerId = setInterval(() => {
      setCount(c => c + 1);
    }, 1000);

    return () => {
      clearInterval(timerId);
    }
  }, []);

  return (
    <div>
      <h2>Hoge</h2>
      <div>{count}</div>
    </div>
  );
};

export default Hoge;