エラーをスローした後にこのコンポーネントがレンダリングされるのはなぜですか?


8

私は現在React JSのドキュメントをフォローしていますが、エラー境界が期待どおりに機能しないという問題が発生しました。ドキュメントで提供されているCodePenに示されている例と、インターネットで見つけた他のいくつかの簡単な例を複製してみましたが、デモと同じように機能しておらず、苦労しています理由を理解する。

正確な問題は、BuggyCounterコンポーネントが余分にレンダリングされるため、エラーが2回スローされることです。コンポーネントが2度目にレンダリングされる理由がわかりません。

この最小限の例をご覧ください。

import React, { Component } from 'react';

function App() {
  return (
    <ErrorHandler>
      <BuggyCounter />
    </ErrorHandler>
  );
}

class ErrorHandler extends Component {
  constructor(props) {
    super(props);
    this.state = {
      error: false,
      errorInfo: null
    }
  }

  componentDidCatch(error, errorInfo) {
    this.setState({ error, errorInfo });
  }

  render() {
    console.log('rendering ErrorHandler. ' + (this.state.error ? "error" : "no error"));
    if(this.state.error) {
      return <p>Error</p>
    }
    return this.props.children;
  }
}

class BuggyCounter extends Component {
  constructor(props) {
    super(props);
    this.state = { counter: 0 };
  }

  handleClick = () => {
    this.setState(({ counter }) => ({
      counter: counter + 1
    }));
  };

  render() {
    console.log('rendering BuggyCounter. count: ' + this.state.counter);
    if (this.state.counter === 5) {
      throw new Error('I crashed!');
    }
    return <h1 onClick={this.handleClick}>{this.state.counter}</h1>
  }
}

export default App;

BuggyCounterコンポーネントは、<p>「エラー」(これは望ましい効果です)をレンダリングするタグに置き換えられていますが、これはほんの一瞬です。その直後、デフォルトのエラーページが表示され、エラー境界の目的が無効になっています。

これが私のコンソールです:

私のエラーとデバッグメッセージ

このトピックについて提供していただける情報があれば幸いです。

一時的な解決策:

これは私の質問への回答ではありませんが、冗長なレンダリングを防ぐ1つの方法は、componentDidUpdateではなくからエラーをスローすることですrender

  render() {
    console.log('rendering BuggyCounter. count: ' + this.state.counter);
    return <h1 onClick={this.handleClick}>{this.state.counter}</h1>
  }

  componentDidUpdate() {
    if(this.state.counter === 5)
      throw new Error('I crashed');
  }

いい質問です、なぜ私にはアイデアがありませんが、おそらくコンポーネントがエラーをスローすると、それはそれ自体を再レンダリングしますか?全く分からない。
Vencovsky


1
ここで奇妙な点は、エラーをスローする前にログを追加するとcomponentDidCatch、エラーが2回スローされますが、componenDidCatch1回しか渡されないということです。
Vencovsky

ここでは同じ@Prasanna
Vencovsky

回答:


3

編集2:

さて、問題は反応バージョン16.12.0にあります。これを16.0.0に変更しても、2回レンダリングされません。反応バージョンを変更することにより、このコードサンドボックスこれをテストできます。

これは、反応githubに追加するのに適した問題です。

おそらく内部的には、reactコアコードの何かです。したがって、バージョンによっては、2回または1回だけレンダリングされます。


編集:

コンポーネントが再レンダリングされる理由 アイデアはありません。

ただし、エラーページは開発モードのみ表示されるため、componentDidCatch正常に機能しています。


古い/悪い答え

BuggyCounterコンポーネントは、<p>「エラー」(これは望ましい効果です)をレンダリングするタグに置き換えられていますが、これはほんの一瞬です。その直後、デフォルトのエラーページが表示され、エラー境界の目的が無効になっています。

そのonly for a moment部分は真実ではありません。エラーページは、実際には開発のためだけのものであり、本番モードで実行すると表示されません。

そして、私のでわかるように、エラーページを閉じると、エラーコンポーネントが表示されます。

これはこの回答で説明されています

そのため、react docsによって提供されるデモバージョンでは、構成自体のためにエラーページは表示されません。コード自体ではありません。コードは正常に機能しています。エラーページを閉じて結果を確認してください。


BuggyCounter二回時にレンダリングされた取得する必要がありますstate.counter === 5ログを示しているため「レンダリングBuggyCounterカウント:5」を2回。なぜErrorHandler余分な時間がレンダリングされるのか説明したと思います。
Anthony Yershov

BuggyCounterエラーがスローされた後に追加のレンダリングを実行する理由が不明です。
アンソニー・ヤーショフ

1
@AnthonyYershovは、で状態を変更しているためですcomponentDidCatch。状態が変化すると、コンポーネントが再レンダリングされます。
Prasanna

@Prasannaはい。それがErrorHandler再びレンダリングされている理由です。それは私の質問ではありません。ログを見ると、状態の変化のために再レンダリングされるBuggyCounter前に余分な時間がレンダリングされていますErrorHandler
アンソニー・ヤーショフ

1
この問題がReact 16.0.0に存在しないことを確認できました。この情報を提供していただき、react githubでこの問題を提起していただきありがとうございます。
アンソニー・ヤーショフ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.