React

ReactのErrorBoundaryで内部のエラーをキャッチする

Error Boundaryとは、自身の子コンポーネントツリーで発生したJavaScriptのエラーをキャッチ・記録しフォールバックのUIを表示するコンポーネントです。 例えるなら、`try/catch`構文を行うコンポーネントのようなものと言えます。

Error Boundary とは、自身の子コンポーネントツリーで発生した JavaScript のエラーをキャッチ・記録しフォールバックの UI を表示するコンポーネントです。

例えるなら、try/catch 構文を行うコンポーネントのようなものと言えます。

ErrorBoundary は次のエラーをキャッチできないことに中止してください。

  • イベントハンドラ
  • 非同期コード(例:setTimeout や requestAnimationFrame のコールバック)
  • サーバーサイドレンダリング
  • (子コンポーネントではなく)error boundary 自身がスローしたエラー

エラーがキャッチされない場合の動作

ErrorBoundary の詳細を見る前に、エラーがキャッチされない場合の動作を確認しておきましょう。

React16 からコンポーネントツリー全体がアンマウントされます。

下記の簡単なコードを使って確認してみます。

const Red = () => {
  return (
    <div style={{backgroundColor: "red", flex: 1, height: 100 }}>Red Area</div>
  )
}
 
const Green = () => {
  return (
    <div style={{backgroundColor: "green", flex: 1 ,height: 100 }}>Green Area</div>
  )
}
const Blue = () => {
  return (
    <div style={{backgroundColor: "blue", flex: 1 ,height: 100}}>Blue Area</div>
  )
}
 
function App() {
  return (
    <div style={{ display: "flex" }}>
      <Red />
      <Green />
      <Blue />
    </div>
  )
}
 
export default App;

スクリーンショット 2021-06-20 20.16.22

Red コンポーネント内で恣意的にエラーを発生させます。

const BadComponent = () => { throw new Error("something went wrong") }
 
const Red = () => {
  return (
    <div style={{backgroundColor: "red", flex: 1, height: 100 }}>
      Red Area
      <BadComponent />
    </div>
  )
}

画面が真っ白になってしまいました。

スクリーンショット 2021-06-20 20.18.33

Error Boundaryコンポーネントの作成

真っ白な画面が表示されてしまうのはユーザーにとってあまりにも不便ですので、Error Boundary コンポーネントを作成してエラーが発生した際の UI を用意しましょう。

以下いずれかのライフサイクルメソッドを実装したクラスコンポーネントは Error Boundary コンポーネントとして扱われます。

公式の Error Boundary コンポーネントの例をそのまま掲載します。

export default 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; 
  }
}

static getDerivedStateFromError

このライフサイクルはフォールバック UI を描画するために使用されます。

getDerivedStateFromError() は子孫コンポーネントによってエラーがスローされた際に呼び出されます。パラメーターとしてスローされたエラー受け取り、state を更新するための値を返す必要があります。

componentDidCatch

このライフサイクルは主にロギングなどの処理に使用されます。

componentDidCatch は同じく子孫コンポーネントによってエラーがスローされた際に呼び出されます。 パラメーターとしてスローされたエラーとスタックトレース情報を受け取ります。

render

render メソッドでは、getDerivedStateFromError によってエラーをキャッチした状態であるならば、フォールバック UI を描画するようにします。

それ以外の場合には、子要素をそのまま描画します。

Error Boundaryコンポーネントの配置

トップレベルに配置

作成した Error Boundary コンポーネントを配置します。 まずはトップレベルに配置してみましょう。その場合には、すべての子孫コンポーネントのエラーをキャッチしてアプリケーション全体にフォールバックの UI が描画されます。

index.js を編集します。

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import ErrorBoundary from './components/ErrorBoundary'
 
ReactDOM.render(
  <ErrorBoundary>
    <App />
  </ErrorBoundary>,
  document.getElementById('root')
);

スクリーンショット 2021-06-20 20.42.12

個別のコンポーネントに配置

Error Boundary コンポーネントは、個別のコンポーネントずつラップして配置できます。 その場合、エラーが発生したコンポーネント以外の箇所はフォールバックの UI を表示せずにそのままの状態を維持することになります。

const Red = () => {
  return (
    <ErrorBoundary>
      <div style={{backgroundColor: "red", flex: 1, height: 100 }}>
        Red Area
        <BadComponent />
      </div>
    </ErrorBoundary>
  )
}
 
const Green = () => {
  return (
    <ErrorBoundary>
      <div style={{backgroundColor: "green", flex: 1 ,height: 100 }}>Green Area</div>
    </ErrorBoundary>
  )
}
const Blue = () => {
  return (
    <ErrorBoundary>
      <div style={{backgroundColor: "blue", flex: 1 ,height: 100}}>Blue Area</div>
    </ErrorBoundary>
  )
}

今度は Red コンポーネントのみにフォールバック UI が描画されました。

スクリーンショット 2021-06-20 20.55.32


Contributors

> GitHub で修正を提案する
この記事をシェアする
はてなブックマークに追加

関連記事