浜松のWEBシステム開発・スマートフォンアプリ開発・RTK-GNSS関連の開発はお任せください
株式会社シーポイントラボ
TEL:053-543-9889
営業時間:9:00~18:00(月〜金)
住所:静岡県浜松市中区富塚町1933-1 佐鳴湖パークタウンサウス2F

【React】コンポ―ネントのエラーハンドリングをするコンポーネント

 バージョン 16.0.0 以降のReact はエラーが起こったことを隠しません。小さなエラーだとしてもそれが例外を投げるならば画面を真っ白にします。

class LoginPage extends Component {
  render() {
    throw Error('hoge') // 例外を投げる
    return <div/>
  }
}


 この状態になると何が原因になったかコンソールに DOM 構造と共に詳しく内容が現れます。例ではコンポーネント名のみで分かりやすいですが実際は div などの素朴な DOM 要素も併せて表示されるので細かくコンポーネントを切り分けていない場合、読みにくいことになります。コーディングの分かりやすさ、再利用のしやすさもありますしコンポーネントは細かく分けるべきです。
 この画面を制御する Error Boundary という方法があります。
Error Boundary – React
 使い方は Error Boundary になるコンポーネントを定義しエラーをキャッチしたい範囲をくくるのみです。具体的には次です。

// app.jsx 的な全体のルートコンポーネントである App を覆う
<ErrorBoundary>
  <App/>
</ErrorBoundary>
import * as React from 'react';

export default class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      hasError: false,
      error: null,
      errorInfo: null,
    };
  }
  /**
   * このメソッドか componentDidCatch があればエラーキャッチ用コンポーネント
   * 併用もOK
   * @param {Error} error
   * @return {{hasError: boolean}}
   */
  static getDerivedStateFromError(error) {
    // 次のレンダリングでフォールバック UI が表示されるように状態を更新します。
    return { hasError: true };
  }

  /**
   * このメソッドか getDerivedStateFromError があればエラーキャッチ用コンポーネント
   * 併用もOK
   * @param {Error} error
   * @param {React.ErrorInfo} errorInfo
   */
  componentDidCatch(error, errorInfo) {
    // エラー報告サービスにエラーを記録することもできます。
    this.setState({error, errorInfo})
  }

  render() {
    if (this.state.hasError) {
      // エラー時の表示
      return <div>
        <h1>JavaScriptの致命的エラー</h1>
        <pre>{this.state.error?.message}</pre>
        <pre>{this.state.errorInfo?.componentStack}</pre>
      </div>;
    }
    // エラーがない時は子(括った内部のコンポーネント)を表示
    return this.props.children;
  }
}

 この様にすると次図の様になります。これによって真っ白画面でなくエラーが起こったと開発者ツールを見ないユーザにも伝えることができます。

 図では真っ白ですがデザインを気にするならば次の様に画面構成のフレーム内に収めるのが無難そうです。

function App() {
  return (
      <Fragment>
        <Header/>
        <div>
          <SideBar/>
          <ErrorBoundary>
            <Content/>
          </ErrorBoundary>
        </div>
      </Fragment>
  )
}
  • この記事いいね! (0)