Error Boundaries
元件相信大家不陌生,通常會用在react的根節點。其又叫錯誤邊界元件。是在 React 16 中引入的,具體來說是 React 16.0.0,釋出於 2017 年 9 月。
class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; } static getDerivedStateFromError(error) { // 更新 state 使下一次渲染可以顯示回退 UI return { hasError: true }; } componentDidCatch(error, info) { // 可以在這裏記錄錯誤日誌,比如傳送到日誌服務 console.log(error, info); } render() { if (this.state.hasError) { // 渲染出錯時的備用 UI return <h1>Something went wrong.</h1>; } return this.props.children; } } function MyComponent() { throw new Error('This is an error!'); return <div>My Component</div>; }
在 React 16 之前,如果元件渲染過程中發生錯誤,整個 React 元件樹會因此崩潰,並且錯誤會傳播到根元件,導致整個應用不可用。React 16 引入了錯誤邊界後,開發者能夠更好地控制錯誤,防止應用的崩潰,並透過顯示備選 UI 來提升使用者體驗。
錯誤邊界是 React 團隊為增強健壯性和穩定性做出的重要改進之一,尤其是在構建大型應用時,能夠極大提高對錯誤的容錯能力。
Error Boundaries
舉個例子,假設你有一個元件負責從API獲取用戶數據。如果網路出現問題,請求可能會失敗。如果沒有錯誤邊界,這可能會導致整個React元件樹崩潰。但有了錯誤邊界,你就可以將錯誤限制在那個元件內部,並提供一個備用的用戶界面,比如顯示一個錯誤訊息。
錯誤邊界主要依賴兩個生命週期方法:
static getDerivedStateFromError(error):當子元件丟擲錯誤時,這個方法會被呼叫,允許你更新元件的狀態,以便渲染一個備用的用戶界面。
componentDidCatch(error, info):這個方法用於記錄錯誤資訊,方便除錯。
錯誤邊界的限制 • 錯誤邊界無法捕獲事件處理器中的錯誤。需要手動在事件處理器中使用 try-catch 。 • 它不能捕獲非同步程式碼中的錯誤(例如 setTimeout、Promise 中的錯誤)。 • 服務端渲染期間發生的錯誤也不會被錯誤邊界捕獲。
如何在Next.js中使用錯誤邊界
首先,我們建立一個錯誤邊界元件:
// components/ErrorBoundary.js import React from 'react'; class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; } static getDerivedStateFromError(error) { // 當捕獲到錯誤時,更新狀態以顯示備用UI return { hasError: true }; } componentDidCatch(error, errorInfo) { // 將錯誤資訊記錄到控制檯或外部服務 console.error("Error occurred:", error, errorInfo); } render() { if (this.state.hasError) { // 如果捕獲到錯誤,渲染備用UI return <h1>出了點問題,請稍後再試。</h1>; } // 否則,正常渲染子元件 return this.props.children; } } export default ErrorBoundary;
然後,我們可以在Next.js的頁面中使用這個錯誤邊界:
// pages/index.js import ErrorBoundary from '../components/ErrorBoundary'; import FaultyComponent from '../components/FaultyComponent'; export default function Home() { return ( <div> <h1>歡迎使用Next.js錯誤邊界示例</h1> <ErrorBoundary> <FaultyComponent /> </ErrorBoundary> </div> ); }
接下來,我們可以在一個元件中模擬一個錯誤:
// components/FaultyComponent.js import React from 'react'; const FaultyComponent = () => { // 模擬一個錯誤 throw new Error("這是一個模擬的錯誤!"); return <div>你永遠不會看到這段文字。</div>; } export default FaultyComponent;
當你訪問主頁時,應用不會崩潰,而是會顯示錯誤邊界提供的備用UI:“出了點問題,請稍後再試。”
改進備用UI
備用UI只是一個簡單的錯誤訊息。你可以使其更加友好和有用,比如新增重試按鈕、錯誤日誌服務,或者建議使用者聯絡支援。
這裏是一個改進後的備用UI示例:
// components/ErrorBoundary.js import React from 'react'; class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; } static getDerivedStateFromError(error) { return { hasError: true }; } componentDidCatch(error, errorInfo) { console.error("錯誤:", error, errorInfo); // 你也可以將錯誤資訊傳送到外部服務 } handleRetry = () => { this.setState({ hasError: false }); }; render() { if (this.state.hasError) { return ( <div> <h2>哎呀,出錯了。</h2> <p>請嘗試重新整理頁面或聯絡支援。</p> <button onClick={this.handleRetry}>重試</button> </div> ); } return this.props.children; } } export default ErrorBoundary;
處理非同步錯誤
錯誤邊界不會自動捕獲非同步程式碼中的錯誤。如果你在使用非同步函式或Promises,你需要在這些程式碼中手動處理錯誤。
這裏是一個處理非同步錯誤的示例:
// components/AsyncComponent.js import React, { useState, useEffect } from 'react'; const AsyncComponent = () => { const [data, setData] = useState(null); const [error, setError] = useState(null); useEffect(() => { const fetchData = async () => { try { const res = await fetch('/api/data'); if (!res.ok) { throw new Error("網路響應不正常"); } const json = await res.json(); setData(json); } catch (err) { setError(err); } }; fetchData(); }, []); if (error) { return <div>錯誤:{error.message}</div>; } return data ? <div>{data.message}</div> : <div>載入中...</div>; }; export default AsyncComponent;
在這個例子中,如果在獲取資料時發生錯誤,我們會顯示一個使用者友好的錯誤訊息,而不是讓整個應用崩潰。
Next.js中的伺服器端錯誤處理
Next.js提供了內建的伺服器端錯誤頁面。例如,你可以透過自定義pages/_error.js檔案來更優雅地處理伺服器端錯誤:
// pages/_error.js function Error({ statusCode }) { return ( <p> {statusCode ? `伺服器發生了錯誤 ${statusCode}` : '客戶端發生了錯誤'} </p> ); } Error.getInitialProps = ({ res, err }) => { const statusCode = res ? res.statusCode : err ? err.statusCode : 404; return { statusCode }; }; export default Error;
透過這種方式,Next.js會為伺服器端錯誤顯示一個自定義的錯誤頁面,而你可以使用錯誤邊界來處理客戶端渲染錯誤。
結束
以上就是Next.js中處理異常的方式,希望對你有用。