今回は、Reactでのエラーハンドリングの方法について調べてまとめました。標準のErrorBoundaryとライブラリであるreact-error-boundaryを使用した方法について解説します。標準のErrorBoundaryの問題点をreact-error-boundaryでは克服しているようです。
初めに
どもども~先週の遅れを爆速で取り戻している龍ちゃんです。先週はぬるっと四連休があったこともあり頭がぼーっとしていましたね。今週の僕は待ちと技術検証の時間だったので心に余裕がある状態で、作業に没頭しています。
Reactでのエラーハンドリングの方法についての第何弾かわかりませんね。エラーハンドリングの方法に関して言えば、あらゆるパターンの方法が存在しています。今回は、標準のエラーハンドリングとライブラリ【react-error-boundary】を使用したエラーハンドリングを紹介します。バージョンが4に上がってから、書き方が変わりました!!ここはバージョン3までの書き方です!。
それでは初めて行きます。
標準のエラーハンドリング
こちらはReactの公式ページに乗っています。React16以降では、エラーが発生した場合コンポーネントがアンマウントされて真っ白な画面が表示されます。デバック時は開発者ツールを使えばエラーがのぞけますが、デプロイ後にエラーが発生した際に何も表示されなければ問い合わせが殺到もしくはすっとブラウザバックされてしまいますね。エラーっぽくてちょっと良い感じのエラー画面を表示されたらうれしいですよね。
標準のエラーハンドリングの問題点
エラーハンドリングするための意図は上記で示した通りです。ですが、標準のエラーハンドリングでは取得できないエラーがあります。こちらは公式サイトにもでかでかと乗っています。
- イベントハンドラ(詳細)
- 非同期コード(例:
setTimeout
やrequestAnimationFrame
のコールバック) - サーバサイドレンダリング
- (子コンポーネントではなく)error boundary 自身がスローしたエラー
意外とこの制限困りますね。イベントハンドラと非同期コードのエラーが捕まらないのがなかなか困ります。
この制限があるので標準のエラーハンドリングだけだと苦しいものがあったりします。回避する方法ももちろんあるのですが、とりあえず構築の方法について説明します。
コーディング
コーディングの方法について説明していきます。static getDerivedStateFromError
かcomponentDidCatch
をどちらか一方もしくは両方を設定することでエラーハンドリングになります。
import React, { ErrorInfo } from 'react';
export default class ErrorBoundary extends React.Component<
{ children: React.ReactNode },
{ hasError: boolean; errorMessage: string }
> {
constructor(props: { children: React.ReactNode }) {
super(props);
this.state = { hasError: false, errorMessage: '' };
}
static getDerivedStateFromError(error: Error) {
// ここでエラーを受け取る
// ここでStateの変更を行って処理を振り分けたりする。
return { hasError: true, errorMessage: error.message };
}
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
// ログに通知したりする部分
console.error(error, errorInfo);
}
render() {
const btnClick = () => {
window.location.reload();
};
if (this.state.hasError) {
// You can render any custom fallback UI
return (
<>
Something went wrong.{this.state.errorMessage}
</>
);
}
return this.props.children;
}
}
componentDidCatch
はエラー情報をログに書き込んだりする処理を行います。static getDerivedStateFromError
ではエラーを取得したら変数を書き換える処理を行います。取得するstate
で定義をしておけば、メッセージだけでなく情報を追加で送信することができます。
とりあえず、先ほど説明を入れたように標準のエラーハンドリングでは取得できない問題があります。それを解決するための手法としてライブラリ【react-error-boundary】を使用する方法があります。
使い方としては、こちらのような使い方になります。
<ErrorBoundary>
<ErrorPage />
</ErrorBoundary>
react-error-boundary
こちらのライブラリでは、標準のエラーハンドリングでは対応できないエラーに対応することができるようになっているようです。勉強に利用したサイトを下に列挙しておきます。
とりあえず、めちゃめちゃわかりやすい参考サイトがあったので置いています。こちらのサイトでもわかるように解説したいと思います。
セットアップ
とりあえず、セットアップをしていきましょう。バージョンが4に上がってから、書き方が変わりました!!ここはバージョン3までの書き方です!。
yarn add react-error-boundary
ライブラリはこちらでインストールが終了します。
コーディング
コーディングの基本的な使用方法としては以下になります。
import { ErrorBoundary, FallbackProps } from 'react-error-boundary';
export const ErrorBoundaryPage = () => {
return (
<>
<ErrorBoundary FallbackComponent={ErrorFallback} onError={onError}>
<ErrorPage />
</ErrorBoundary>
</>
);
};
const ErrorFallback = ({ error, resetErrorBoundary }: FallbackProps) => {
return (
<>
<pre>react-error-boundary {error.message}</pre>
<button type="button" onClick={resetErrorBoundary}>
reset button
</button>
</>
);
};
const onError = (error: Error, info: { componentStack: string }) => {
console.error(error, info);
};
ライブラリで取得したErrorBoundary
コンポーネントでコンポーネントを挟むことで標準のエラーハンドリングと同等の処理を挟むことができます。標準のエラーハンドリングではrender
でレンダリングを変更していましたが、こちらの場合はFallbackComponent
にコンポーネントを指定することで表示が切り替わります。しかも、resetErrorBoundary
を処理するとエラー画面から自動で復帰します。onError
ではエラー情報を取得してログに記録する部分を記述します。
標準のエラーハンドリング問題点解消方法
標準のエラーハンドリングでは取得できないエラーを解消するためにエラーを伝搬する機能が【react-error-boundary】には用意されています。その代わり明示的にエラーを通知する必要があります。以下のフックを用いてエラーを通知します。
import { useErrorBoundary } from 'react-error-boundary';
const { showBoundary } = useErrorBoundary();
showBoundary(new Error('error'));
try~catch
を使用してエラーが発生したタイミングでuseErrorBoundary
から取得した関数で通知する必要があります。こちらを使用することで、イベントハンドラ中や非同期コードの処理中にエラーが発生した場合に無事エラーを通知することができます。
終わりに
お疲れ様です。今回はReactでのエラーハンドリングについて言及していきました。まだ、非同期コードのエラーをキャッチすることはできません。非同期通信でAxiosを使っている場合は、こちらの記事の【Axios Interseptor】と今回の【react-error-boundary】組み合わせで非同期コードのエラーハンドリングを行うことができそうです。次回のブログはそちらの記事でまとめていきます。
ではでは~またね~