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;
Red コンポーネント内で恣意的にエラーを発生させます。
const BadComponent = () => { throw new Error("something went wrong") }
const Red = () => {
return (
<div style={{backgroundColor: "red", flex: 1, height: 100 }}>
Red Area
<BadComponent />
</div>
)
}
画面が真っ白になってしまいました。
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')
);
個別のコンポーネントに配置
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 が描画されました。