Section 1:痛點 — JavaScript 錯誤讓整個頁面崩潰
你有沒有遇過這種情況:app 在某個用戶端出現了一個罕見的 API 回應—— 比如 user.profile 是 null—— 然後整個畫面就變成一片空白,連錯誤訊息都看不到。 用戶茫然地重新整理,然後放棄。
這就是 React 未捕獲錯誤的預設行為:整個 React 元件樹 unmount,白屏。
為什麼 try/catch 攔不住渲染錯誤?
React 的 render 是在 React 內部的調度機制中執行的,而不是在你的程式碼的呼叫堆疊上。 當 React 呼叫 UserCard 的 render 並拋出錯誤時, 錯誤會沿著 React 自己的 fiber 樹往上傳播,不是沿著你的 JavaScript 呼叫堆疊。 所以包在外面的 try/catch 完全攔不到。 Error Boundary 是 React 提供的特殊機制,讓你可以「在元件樹層面」攔截這類錯誤。
沒有 Error Boundary
- • 任何一個子元件拋出錯誤
- • 整個 React tree 崩潰並 unmount
- • 用戶看到白屏,完全不知道發生什麼
- • 你也不知道錯在哪,因為沒有上報
有 Error Boundary
- • 錯誤被最近的 Error Boundary 攔截
- • 顯示優雅的 fallback UI(「發生了一點問題」)
- • 頁面其他部分正常運作
- • 錯誤資訊上報到監控服務(Sentry 等)
Section 2:Class Component Error Boundary
Error Boundary 目前只能用 class component 實作。這是 React 刻意保留的少數幾個「必須用 class」的場景之一。
為什麼必須用 class component?因為 Error Boundary 需要兩個特殊的生命週期方法:getDerivedStateFromError(在渲染階段捕獲錯誤並更新 state)和componentDidCatch(在提交階段捕獲錯誤,適合做 side effect 如上報到監控服務)。 目前 React 還沒有提供對應的 Hook,所以無法用函式元件實作。
使用方式
Error Boundary 的粒度由你決定。可以包整個 app,也可以只包特定的 widget。 粒度越細,錯誤影響範圍越小:
Section 3:Suspense — 處理「正在載入中」的狀態
Error Boundary 處理「出錯了」的情況,而 Suspense 處理「正在等待」的情況。 它讓你用宣告式的方式描述 loading 狀態,不需要在每個元件裡寫 isLoading &&。
最常見的用法:React.lazy 程式碼分割
三個 Suspense 使用場景
1. Code Splitting
用 React.lazy 把大型元件拆成獨立 chunk, 首次載入只下載必要的程式碼,大幅減少 bundle size。
2. 資料請求
配合支援 Suspense 的 library(SWR、React Query、Relay), 資料載入中時自動顯示 fallback,不需要手動管理 isLoading。
3. Server Component
Next.js App Router 原生支援。Server Component 在伺服器端取資料時, 客戶端顯示 Suspense fallback,資料就緒後串流回來。
Next.js 的 loading.tsx — Suspense 的語法糖
在 Next.js App Router 中,你不需要手動寫 Suspense——只要在資料夾放一個 loading.tsx, Next.js 會自動把它包進 Suspense 的 fallback:
Section 4:搭配使用 — 完整的容錯架構
生產環境中,ErrorBoundary 和 Suspense 幾乎總是一起出現: Suspense 處理正常的「等待中」流程,ErrorBoundary 處理意外的「出錯了」情況。
標準的組合模式
Next.js App Router 中的 error.tsx
就像 loading.tsx 是 Suspense 的語法糖,error.tsx 就是 Error Boundary 的語法糖—— Next.js 自動幫你創建一個 Error Boundary,用 error.tsx 當 fallback:
Section 5:react-error-boundary 套件 — 不要自己寫 class
自己實作 class Error Boundary 沒有問題,但有一個成熟的套件可以幫你省掉樣板程式碼, 並提供更多功能:react-error-boundary。
這個套件由 Brian Vaughn(React 核心團隊前成員)維護,是業界最廣泛使用的 Error Boundary 解法。 它把自己寫 class 元件的工作抽象掉,讓你可以完全用函式元件的方式使用 Error Boundary。
基本用法:FallbackComponent
useErrorBoundary — 在 async 操作中手動觸發
前面提過,Error Boundary 捕獲不到非同步錯誤(例如 fetch 失敗、setTimeout 內部的錯誤)。useErrorBoundary 讓你把這些錯誤手動「拋進」最近的 Error Boundary:
resetKeys — 根據 props 改變自動重置
當用戶切換路由(例如從 userId=1 切到 userId=2),你希望 Error Boundary 自動重試,而不是一直顯示錯誤 UI。resetKeys 讓你指定「某個 prop 改變時,自動重置 Error Boundary」:
react-error-boundary vs 自己實作的比較
自己實作(class component)
- • 需要寫 class component 樣板
- • 無法在函式元件中使用 Hook
- • 無 useErrorBoundary(手動拋錯很麻煩)
- • resetKeys 要自己實作
- • 適合:不想加依賴的小型專案
react-error-boundary 套件
- • 完全函式元件的使用方式
- • useErrorBoundary 輕鬆處理 async 錯誤
- • resetKeys 自動根據 props 重置
- • onError / onReset callbacks
- • 適合:幾乎所有生產環境專案