【React】Can't perform a React state update on an unmounted componentの原因と対処法

今回はReactで、非同期やタイマー処理を使った場合に発生するWarningの内容と対処法についてご紹介します。 後片付けの処理を忘れると起こりがちなため注意が必要です。

エラーメッセージ

Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.

意訳すると以下のようになります。

アンマウントされたコンポーネントStateの更新を行っており、結果的にメモリリークしているのでちゃんとcomponentWillUnmountでタスクを処理してくれ」

発生するケース・原因

よくあるのが下記のような書き方をしている場合です。 componentDidMountStateを書き換える可能性のある処理を定期実行、もしくはPromise等の非同期で実行して、その間のこのコンポーネントをアンマウントしたようなケースです。

予約された処理が実行される段階では、対象となるコンポーネントはアンマウントされているため更新ができなくなります。

例のようにsetIntervalで定期実行していると、タスクを止めるコンポーネントが無くなってしまっているので、メモリリークに繋がります。

import React from 'react';

class LeakComponent extends React.Component {
  // setIntervalのhandle
  _handle = 0;

  // コンストラクタ
  constructor(props) {
    this.state = {
      // 現在時刻
      now: new Date(),
    };
  }

  componentDidMount = () => {
    // 毎秒現在時刻をsetStateする処理を定義
    this._handle = setInterval(() => {
      this.setState({
        now: new Date(),
      });
    }, 1000);
  };

  render = () => {
    return <>{this.state.now.toString()}</>;
  };
}

export default LeakComponent;

対処法

コンポーネントがアンマウントされた後でStateを更新するような処理が発生する可能性がある場合、componentWillUnmountでそれらのタスクを必ず処理するようにしましょう。

先ほどの例では、以下のような記載を追加すればOKです。

componentWillUnmount = () => {
  // clearIntervalで設定された処理を解除
  clearInterval(this._handle);
};

まとめ

今回はCan't perform a React state update on an unmounted component...Warningの原因と対処法についてご紹介しました。 非同期等を絡めだすと頻出となる警告なので、そういった処理は外部ライブラリに任せてしまうのも手かもしれません。

SNSでシェアする