Uncaught Error: Maximum update depth exceeded. React limits the number of nested updates to prevent infinite loops.

React
スポンサーリンク
language
react-dom.development.js:4379 Uncaught Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.

このエラーはReactのレンダリング時にsetStateが呼ばれて無限ループに陥った時にでるエラーです。

このエラー文を翻訳すると以下のようになります。

最大更新数を超えました。 これは、コンポーネントがcomponentWillUpdateまたはcomponentDidUpdate内でsetStateを繰り返し呼び出す場合に発生する可能性があります。 Reactは、ネストされた更新の数を制限して無限ループを防ぎます。

このエラーを解消するには無限ループとなっているコードを変更する必要があります。

今回はこのエラーが出たときの解決方法と原因をご紹介します。

スポンサーリンク

解決方法はsetStateを呼び出さいようにすること

クリックイベントなどのイベントハンドラでsetStateを含む関数を実行しないようにすると無限ループを防ぐことができます。

16行目のようにonClick={this.handleOpen}と書いて関数にカッコをつけないか、

または20行目のようにonClick={() => this.handleOpen(false)}と書いて、イベントハンドラにアロー関数として定義すると無限ループを解消できます。

class OpenComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      open: false,
    };
    this.handleOpen = this.handleOpen.bind(this);
  }

  handleOpen(is_open=true) {
    this.setState({ open: is_open);
  }

  render() {
      return (
          <div>
            <button onClick={this.handleOpen}>
                OPEN
            </button>
            <button onClick={() => this.handleOpen(false)}>
                CLOSE
            </button>
          <div>
      )
  }
}

原因はsetStateを呼び出すと再レンダリングされるから

無限ループになる原因はクリックイベントなどに定義したsetStateを含む関数がレンダリング時に発火することです。

setStateは呼ばれると再レンダリングします。

setState() が呼び出されたおかげで、React は state が変わったということが分かるので、render() メソッドを再度呼び出して、画面上に何を表示すべきかを知ります。

https://ja.reactjs.org/docs/state-and-lifecycle.html

具体的に無限サイクルに陥るサイクルは以下のとおりです。

render を実行→this.handleOpen を実行→setState を実行→再度 render を実行→繰り返し

以下のコードではコンポーネントがレンダリングされるたびにクリックイベントに定義したthis.handleState(true)が発火します。

class OpenComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      open: false,
    };
    this.handleOpen = this.handleOpen.bind(this);
  }

  handleOpen(is_open=true) {
    this.setState({ open: is_open);
  }

  render() {
      return (
          <div>
            <button onClick={this.handleOpen()}> // setStateを呼び出すので無限ループ
                OPEN
            </button>
            <button onClick={this.handleOpen(false)}> // setStateを呼び出すので無限ループ
                CLOSE
            </button>
          <div>
      )
  }
}

まとめ

render内でsetStateを使っていたり、setStateを呼び出している関数がないか確認してください。

setStateを呼び出していたら次のように変更してください。

  • 関数名を渡す(関数名にカッコを付けない)
  • アロー関数を使用する

Reactのレンダリング時にsetStateが呼ばれないようになり無限ループのエラーが解消されます。

class OpenComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      open: false,
    };
    this.handleOpen = this.handleOpen.bind(this);
  }

  handleOpen(is_open=true) {
    this.setState({ open: is_open);
  }

  render() {
      return (
          <div>
            // <button onClick={this.handleOpen()}> // setStateを呼び出すので無限ループ
            <button onClick={this.handleOpen}> // 関数名を渡す(関数名にカッコを付けない)
              OPEN
            </button>
            
            // <button onClick={this.handleOpen(false)}> // setStateを呼び出すので無限ループ
            <button onClick={() => this.handleOpen(false)}> // アロー関数を使用する
              CLOSE
            </button>
          <div>
      )
  }
}

コンポネントに関数を渡す方法はこちらが参考になります。

コンポーネントに関数を渡す – React
ユーザインターフェース構築のための JavaScript ライブラリ

この記事でわからないコードなどがあれば、書籍で勉強するのがおすすめです。
プログラミングの技術の移り変わりは早いので最新版の書籍を購入することをお勧めします。
中古本を買って勉強したけど、今は使われない技術だったということはよくあります。

javascript・Reactでおすすめの書籍をご紹介します。

りーほー
りーほー

JavaScriptを基礎からしっかり学びたい方におすすめ!

りーほー
りーほー

JavaScriptを基礎から応用までガッツリ学びたい方におすすめ!

りーほー
りーほー

Reactの概念や仕組みを把握し、開発で使えるReactを学びたい方にオススメ!

タイトルとURLをコピーしました