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

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>
      )
  }
}

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

https://ja.reactjs.org/docs/faq-functions.html

下記に参考書をまとめておきます。

りーほー
りーほー

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

りーほー
りーほー

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

りーほー
りーほー

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

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする


reCaptcha の認証期間が終了しました。ページを再読み込みしてください。

目次