Error Boundaries


以前は、コンポーネント内部のJavaScriptエラーが応答の内部状態を汚染し、次のレンダリングで暗号化エラー(emit crypticerror)を解放していました.これらのエラーは、常にアプリケーションコードの前のステップによって引き起こされるが、反応器は、素子内部でこれらのエラーを防止または回復する方法を提供していない.

Introducing Error Boundaries


UIのエラーは、アプリケーション全体を中断する必要はありません.これらの問題を解決するために、Reaction 16はReactionユーザに「error bounder」という新しい概念を紹介した.
Error boundersは、サブコンポーネントツリーの任意の場所にJavaScriptエラーを記録し、破壊されたコンポーネントツリーではなく、UIのロールバックを表示するReactコンポーネントです.Error境界は、レンダリング中にライフサイクルメソッドとその下のツリー全体の作成者からエラーをキャプチャします.
Error境界では、次のエラーはキャプチャされません.
  • Event handler
  • Asynchronous code (e.g. setTimeout or requestAnimationFrame callbacks)
  • Server side rendering
  • Errors thrown in the error boundary itself (rather than its children)
  • スタティックgetDerivedStateFromError()またはアセンブリDidCatch()がジェネリック構成部品に実装されている場合、構成部品はError境界として機能します.
  • 静的getDerivedStateFromError()-エラーが発生した場合は、ステータスを変更してロールバックUIの表示を支援します.
  • コンポーネントDidCatch()-エラー情報を記録します.
  • class ErrorBoundary extends React.Component {
      constructor(props) {
        super(props);
        this.state = { hasError: false };
      }
    
      static getDerivedStateFromError(error) {
        // Update state so the next render will show the fallback UI.
        return { hasError: true };
      }
    
      componentDidCatch(error, errorInfo) {
        // You can also log the error to an error reporting service
        logErrorToMyService(error, errorInfo);
      }
    
      render() {
        if (this.state.hasError) {
          // You can render any custom fallback UI
          return <h1>Something went wrong.</h1>;
        }
    
        return this.props.children; 
      }
    }
    このようにして実施したError境界は通常の素子のように使用できる.
    <ErrorBoundary>
      <MyWidget />
    </ErrorBoundary>
    Error境界はJavaScriptのcatch{}ブロックと同じですが、構成部品に適用されます.クラス要素のみがError境界になる.実際には、ほとんどの場合、Error boundコンポーネントを宣言するだけで、アプリケーション全体で使用できます.
    Error境界は、その子の要素ツリーにあるエラーのみをキャプチャし、Error境界自体で発生したエラーをキャプチャすることはできません.エラー境界レンダリングエラーメッセージが失敗した場合、エラーはツリーの上部に最も近いエラー境界に伝播します.これらの特性はJavaScriptのcatch{}ブロックにも似ています.

    Live Demo


    Check out this example of declaring and using an error boundary with React 16

    Where to Place Error Boundaries


    Error境界の微細化はあなた次第です.また、最上位ルータを迂回して、サーバ側フレームワークでよく使用されるメッセージを表示することもできます.たとえば、「Something gover fault」などです.また、各コンポーネントを包囲して、競合中にプロジェクト全体を保護することもできます.

    New Behavior for Uncaught Errors


    react 16から、エラーがError境界でキャッチされていないため、react構成部品ツリー全体がアンインストールされます.経験上、反応チームは、エラーUIを表示するよりもUIを完全に削除したほうがいいと考えています.
    例えば、ユーザのUIが正しく表示されない場合、例えば、メッセージングプログラムでは、ユーザが誤った人にメッセージを送信する可能性がある.同様に、金額に関する情報(例えば、エラーの合計)は表示しないほうがよい.
    これは、React 16に移行すると、アプリケーションが以前不明だった既存の競合を発見する可能性があることを意味します.Errorの枠線を追加することで、問題が発生したときにより良いユーザー体験を提供します.
    たとえば、フェイスブックメッセージングは、サイドバー、情報パネル、会話履歴、メッセージ入力を個別のエラー境界にカプセル化します.このUI領域のコンポーネントが競合している場合、残りのコンポーネントはインタラクティブなままになります.
    また、JavaScriptミラーリングサービスを利用するか、または独自に作成することをお勧めします.これにより、本番環境で未処理の例外を学習および変更できます.

    Component Stack Traces


    React 16は、アプリケーションが誤って飲み込んだとしても、開発中にレンダリングされたすべてのエラーをコンソールウィンドウに表示します.エラーメッセージとJavaScript、コンポーネントスタック追跡.これで、どの構成部品ツリーに障害が発生しているかを正確に特定できます.

    コンポーネントスタックトラッキングでは、ファイル名と行番号も表示できます.デフォルトでは、CRAプロジェクトで機能します.

    CRAを使用しない場合は、バーベル設定にプラグインを登録して使用できます.これらの機能は開発者のみが使用し、生産過程で使用すべきではありません.
    stack traceで表される構成部品の名前はFunctionです.nameプロパティに依存します.デフォルトで提供されていない古いブラウザまたはアプライアンスがサポートされている場合はfunctionを使用します.name-polyfillなどの機能.アプリケーションバンドルパッケージにname polyfillを含めることを考慮してください.代替案として
    すべての構成部品に対してdisplayName構成を設定することもできます.

    How About try/catch?


    try/catchは良いですが、コマンドコードでのみ機能します.
    try {
      showButton();
    } catch (error) {
      // ...
    }
    一方、リアクション要素の詳細は、[レンダリング](Render)が宣言形式であることを示しています.
    <Button />
    命令型と宣言型の違いが分からない場合は、コマンド型vs宣言型の記事を読んでください.
    Error BoundaryはReactの宣言的特性を保持し,期待どおりに動作した.たとえば、コンポーネントDidUpdateメソッドがツリーの深い位置に設定されているためにエラーが発生した場合、エラーは最近のエラー境界に正確に伝播します.

    How About Event Handlers?


    Error境界はイベントハンドラのエラーをキャプチャしません.
    エラー境界を使用してイベントハンドラ内部のエラーを復元する必要はありません.イベントハンドラは、レンダリング方法またはライフサイクル方法とは異なり、レンダリング中は機能しません.だから、アクティブなヘンドラーに投げ込まれたとき、スクリーンの反応が見えます.
    イベントハンドラでエラーをキャプチャする必要がある場合は、JavaScript try/catch構文を使用します.
    class MyComponent extends React.Component {
      constructor(props) {
        super(props);
        this.state = { error: null };
        this.handleClick = this.handleClick.bind(this);
      }
    
      handleClick() {
        try {
          // Do something that could throw
        } catch (error) {
          this.setState({ error });
        }
      }
    
      render() {
        if (this.state.error) {
          return <h1>Caught an error.</h1>
        }
        return <button onClick={this.handleClick}>Click Me</button>
      }
    }
    上記の例では、一般的なJavaScript動作を示し、Error bounderは使用しません.

    Naming Changes from React 15


    react 15は、不安定なhandleErrorの名前で非常に限られたError境界機能を含む.この方法は有効ではありません.最初の16βバージョンからコードからComponentDidCatchに変更する必要があります.
    この変更のためにコードを自動的に移行するためにcodemodを提供しました.