debuggingの回で、エラーの読み方を扱いました。今回はエラーが起きたときに、画面をどう壊れさせるかの設計です。
何もしないと、画面がまるごと消える
Reactは、描画中にエラーが起きるとその画面全体を空にします。1つのカードのバグで、ページ全部が真っ白になるということです。
開発中は赤いエラー画面が出るので気づきますが、本番では何も出ません。ユーザーから見えるのは白紙です。
Error Boundaryはクラスで書く
Reactでいまクラスコンポーネントを書く唯一の場面がこれです。描画中のエラーを捕まえる仕組みが、フックとして用意されていないためです。
import { Component } from 'react'
class ErrorBoundary extends Component {
state = { hasError: false }
static getDerivedStateFromError() {
return { hasError: true } // 落ちたことを状態に記録する
}
componentDidCatch(error, info) {
// 本番ではここでエラー監視サービスへ送る
console.error('Caught by ErrorBoundary:', error, info.componentStack)
}
render() {
if (this.state.hasError) {
return (
this.props.fallback ?? (
<div className="p-8">
<h1 className="text-2xl font-bold">画面の表示に失敗しました</h1>
<button type="button" onClick={() => this.setState({ hasError: false })}>
もう一度ためす
</button>
</div>
)
)
}
return this.props.children
}
}
export default ErrorBoundary2つのメソッドが仕事をしています。
getDerivedStateFromError——落ちたことをstateに記録する(表示の切りかえ用)componentDidCatch——記録を送るための場所(監視サービス・ログ)
使うときは、守りたい範囲を包みます。
<ErrorBoundary>
<Routes>…</Routes>
</ErrorBoundary>
どこに置くか
アプリ全体に1つ+壊れても他を生かしたい単位、という二段構えが基本です。
| 置き場所 | 効果 |
|---|---|
アプリ全体(<Routes>の外) | 最後の砦。真っ白を防ぐ |
| ページ単位 | そのページだけ落ちる。ヘッダーやナビは生きる |
| 部品単位(一覧・グラフ・広告枠) | 部品だけ落ちて、周りは表示されたまま |
捕まえられないエラーがある
ここは誤解しやすいところです。Error Boundaryが捕まえるのは描画中のエラーだけです。
| 捕まる | 捕まらない |
|---|---|
| 描画中(JSXを組み立てている最中) | イベントハンドラの中(onClickの処理) |
ライフサイクル・useEffectの中の描画関連 | 非同期処理の中(setTimeout・fetchの.then) |
| 子コンポーネントの描画 | サーバー側の描画(別の仕組みが要る) |
イベントの中はtry/catch、データ取得はライブラリのエラー状態(useQueryのisError)で扱います。
function handleDelete() {
try {
removeBird(bird.id)
} catch (error) {
setMessage('削除できませんでした')
}
}lazyとSuspense——読みこみを分ける
Error Boundaryと同じ「範囲を区切る」考え方で、読みこみにも区切りを入れられます。
import { lazy, Suspense } from 'react'
const BirdDetailPage = lazy(() => import('./pages/BirdDetailPage.jsx'))
<Suspense fallback={<p>よみこみ中…</p>}>
<BirdDetailPage />
</Suspense>lazyにすると、そのページを開いたときに初めてJavaScriptが読みこまれます(コード分割)。最初に配るファイルが小さくなるので、初回表示が速くなります。
Suspenseはその待ち時間に何を出すかの指定です。
公式ドキュメントも見てみる
ja.react.dev外部サイトComponent – React公式のError Boundaryの説明。getDerivedStateFromErrorとcomponentDidCatchの役割分担が書かれていますこのレッスンのまとめ
- Reactは描画中のエラーで画面をまるごと空にする(本番では真っ白)
- Error Boundaryで、壊れる範囲を自分で決める
- いまクラスコンポーネントを書く唯一の場面。ライブラリで代替もできる
getDerivedStateFromErrorで表示を切りかえ、componentDidCatchで記録を送る- 置き方はアプリ全体+落ちても他を生かしたい単位の二段構え
- イベントハンドラと非同期処理の中は捕まらない——
try/catchやライブラリのエラー状態で lazy+Suspenseで読みこみも区切れる。ErrorBoundaryと重ねると3状態が表せる
次からは章が変わって、TypeScriptです。ここまで書いたJavaScriptに型を入れていきます。