React錯誤處理:錯誤邊界指南

React錯誤處理:錯誤邊界指南

有效的錯誤管理對於構建彈性和使用者友好的 React 應用程式至關重要。當您的應用程式遇到意外錯誤時,必須提供一種優雅的方式來處理這些錯誤並將其呈現給使用者,同時保持其功能不變。React 的錯誤邊界(Error Boundaries)為實現這一目標提供了強大的機制,本文將探討它們是什麼、如何實現它們以及它們的最佳實踐。

React 錯誤邊界就像應用程式的安全網。當樹狀結構中的任何元件發生錯誤時,這些邊界會捕獲錯誤,防止整個應用程式崩潰。它們提供了一種顯示回退 UI 和記錄錯誤詳細資訊的方法,讓您可以更優雅地處理錯誤。這是一個很好的工具,可以增強使用者體驗,幫助開發人員在不中斷整個應用程式的情況下發現並解決問題。納入錯誤邊界是提高前端穩定性的明智之舉。

為什麼錯誤邊界對 React 應用程式很重要?

如果沒有錯誤邊界,元件中的一個錯誤就有可能導致整個應用程式癱瘓,造成令人沮喪的使用者體驗,並使開發人員難以確定根本原因。錯誤邊界對 React 應用程式非常重要,原因有以下幾點:

  • 防止應用程式崩潰:錯誤邊界可捕獲其元件樹中的錯誤,防止錯誤在元件層次結構中向上傳播,導致整個應用程式崩潰。這樣,即使發生錯誤,也能確保更穩定、響應更快的使用者體驗。
  • 改善使用者體驗:錯誤邊界不會使應用程式突然崩潰,而是會顯示一個後備使用者介面,告知使用者錯誤並提供更可控的響應。這可以防止使用者產生挫敗感,並允許他們繼續與應用程式進行互動。
  • 隔離錯誤:錯誤邊界有助於將錯誤隔離到特定元件,從而更容易識別和除錯問題的根源。這簡化了開發流程,減少了除錯時間,因為開發人員可以專注於發生錯誤的特定元件。
  • 記錄錯誤:錯誤邊界可用於將錯誤記錄到外部服務或分析平臺。這能為應用程式行為和潛在問題提供有價值的見解,幫助開發人員識別模式、跟蹤錯誤發生情況並確定除錯工作的優先順序。
  • 可維護程式碼:錯誤邊界將錯誤處理邏輯封裝在特定元件中,從而提高了程式碼的可維護性。這樣就更容易理解和修改錯誤處理行為,而不會影響應用程式的其他部分。
  • 優雅的錯誤處理:錯誤邊界可實現優雅的錯誤處理,使開發人員能夠向使用者提供有意義的反饋,並在發生錯誤時保持一致的使用者體驗。這將提升整體使用者體驗,並建立對應用程式的信任。

總之,錯誤邊界在確保 React 應用程式的穩定性和可用性方面發揮著至關重要的作用。它們可以防止意外崩潰,改善使用者體驗,簡化除錯,並提供有關應用程式行為的寶貴見解。

React 應用程式中錯誤邊界的實際實現

在本節中,我們將深入探討錯誤邊界的工作原理,將複雜的問題分解為簡單的部分。我們將構建一個 React 應用程式,建立一個錯誤邊界元件。通過用這個保護層包裹我們的元件,我們就能加強應用程式的抗錯能力,確保更流暢的使用者體驗。

如何建立錯誤邊界元件

錯誤邊界元件是一種特殊的 React 元件,可以捕捉其子元件中發生的錯誤。這樣,您就可以顯示一個後備 UI,而不是讓整個應用程式崩潰。在 React 中,錯誤邊界必須是類元件,因為它們依賴於只有類元件才能使用的兩個特定生命週期方法。請注意,功能元件不能使用這些生命週期方法,因此它們不能成為錯誤邊界。

要建立錯誤邊界元件,您需要建立一個類元件,並實現以下生命週期方法中的一個或兩個:

  • static getDerivedStateFromError():該方法可在出錯後渲染回退使用者介面。
  • componentDidCatch():該方法將錯誤資訊記錄到控制檯或錯誤報告服務中。

首先建立一個新元件 ErrorBoundary.js,作為錯誤邊界。該元件需要定義生命週期方法:static getDerivedStateFromError() 和 componentDidCatch()。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import React, { Component } from 'react';
class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// You can log the error
console.error('Error:', error);
console.error('Error Info:', errorInfo);
}
render() {
if (this.state.hasError) {
return (
<div>
<h2>Something went wrong. Please try again later.</h2>
</div>
);
}
return this.props.children;
}
}
export default ErrorBoundary;
import React, { Component } from 'react'; class ErrorBoundary extends Component { constructor(props) { super(props); this.state = { hasError: false }; } static getDerivedStateFromError(error) { return { hasError: true }; } componentDidCatch(error, errorInfo) { // You can log the error console.error('Error:', error); console.error('Error Info:', errorInfo); } render() { if (this.state.hasError) { return ( <div> <h2>Something went wrong. Please try again later.</h2> </div> ); } return this.props.children; } } export default ErrorBoundary;
import React, { Component } from 'react';
class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// You can log the error 
console.error('Error:', error);
console.error('Error Info:', errorInfo);
}
render() {
if (this.state.hasError) {
return (
<div>
<h2>Something went wrong. Please try again later.</h2>
</div>
);
}
return this.props.children;
}
}
export default ErrorBoundary;

上述程式碼定義了一個名為 ErrorBoundary 的 React 元件,旨在捕捉其子元件中的錯誤。讓我們來分解程式碼:

  1. 匯入語句:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import React, { Component } from 'react';
import React, { Component } from 'react';
import React, { Component } from 'react';

這一行從 react 庫中匯入 React 物件和 Component 類。在 React 中建立類元件需要使用 Component 類。

  1. 類定義:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class ErrorBoundary extends Component {
class ErrorBoundary extends Component {
class ErrorBoundary extends Component {

這裡定義了一個名為 ErrorBoundary 的類,它擴充套件了 Component 類。這意味著 ErrorBoundary 是一個 React 類元件。

  1. 建構函式:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
constructor(props) {
super(props);
this.state = { hasError: false };
}
constructor(props) { super(props); this.state = { hasError: false }; }
constructor(props) {
super(props);
this.state = { hasError: false };
}

constructor 方法用於初始化元件的狀態。在本例中,它將初始狀態設定為 hasError,並將屬性設定為 false。要呼叫父類(Component)的建構函式,就必須呼叫 super(props)

  1. 靜態方法 – getDerivedStateFromError:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
static getDerivedStateFromError(error) {
return { hasError: true };
}
static getDerivedStateFromError(error) { return { hasError: true }; }
static getDerivedStateFromError(error) {
return { hasError: true };
}

此靜態方法是 React 16 中引入的生命週期方法。它在渲染過程中發生錯誤時被呼叫,其目的是根據發生的錯誤更新元件狀態。在這種情況下,它會將 hasError 設為 true

  1. 方法 – componentDidCatch:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
componentDidCatch(error, errorInfo) {
console.error('Error:', error);
console.error('Error Info:', errorInfo);
}
componentDidCatch(error, errorInfo) { console.error('Error:', error); console.error('Error Info:', errorInfo); }
componentDidCatch(error, errorInfo) {
console.error('Error:', error);
console.error('Error Info:', errorInfo);
}

componentDidCatch 是另一個生命週期方法,在渲染過程中出現錯誤後被呼叫。它提供了一個記錄錯誤詳細資訊的機會。在本例中,它會將錯誤和錯誤資訊記錄到控制檯。

  1. 渲染方法:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
render() {
if (this.state.hasError) {
return (
<div>
<h2>Something went wrong. Please try again later.</h2>
</div>
);
}
return this.props.children;
}
render() { if (this.state.hasError) { return ( <div> <h2>Something went wrong. Please try again later.</h2> </div> ); } return this.props.children; }
render() {
if (this.state.hasError) {
return (
<div>
<h2>Something went wrong. Please try again later.</h2>
</div>
);
}
return this.props.children;
}

render 方法負責渲染元件。如果 hasErrortrue ,它會返回一個表示出錯的後備 UI。否則,它會渲染子元件( this.props.children ),當沒有錯誤時,允許正常渲染元件的子元件。

  1. 匯出宣告:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
export default ErrorBoundary;
export default ErrorBoundary;
export default ErrorBoundary;

這一行匯出 ErrorBoundary 元件,使其可用於其他應用部分。

總之,ErrorBoundary 元件將被用作其他元件的包裝器。如果被封裝的元件發生任何錯誤, ErrorBoundary 將捕捉錯誤、更新其狀態、記錄錯誤細節,並渲染一個後備使用者介面來通知使用者出錯了。

如何使用錯誤邊界元件

要使用錯誤邊界元件,請將其包裹在要捕捉錯誤的元件周圍。在此之前,我們將更新錯誤邊界元件中的後備使用者介面,以顯示更合適的資訊。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// ErrorBoundary.js
import React, { Component } from "react";
class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
this.setState({
error: error,
errorInfo: errorInfo,
hasError: true,
});
}
render() {
if (this.state.hasError) {
return (
<div className="bg-red-100 border-l-4 border-red-500 text-red-700 p-4">
<p className="font-bold">Oops! Something went wrong.</p>
<p>This is not a car.</p>
</div>
);
}
return this.props.children;
}
}
export default ErrorBoundary;
// ErrorBoundary.js import React, { Component } from "react"; class ErrorBoundary extends Component { constructor(props) { super(props); this.state = { hasError: false }; } static getDerivedStateFromError(error) { return { hasError: true }; } componentDidCatch(error, errorInfo) { this.setState({ error: error, errorInfo: errorInfo, hasError: true, }); } render() { if (this.state.hasError) { return ( <div className="bg-red-100 border-l-4 border-red-500 text-red-700 p-4"> <p className="font-bold">Oops! Something went wrong.</p> <p>This is not a car.</p> </div> ); } return this.props.children; } } export default ErrorBoundary;
// ErrorBoundary.js
import React, { Component } from "react";
class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
this.setState({
error: error,
errorInfo: errorInfo,
hasError: true,
});
}
render() {
if (this.state.hasError) {
return (
<div className="bg-red-100 border-l-4 border-red-500 text-red-700 p-4">
<p className="font-bold">Oops! Something went wrong.</p>
<p>This is not a car.</p>
</div>
);
}
return this.props.children;
}
}
export default ErrorBoundary;

如果在 ErrorBoundary 範圍內發生任何錯誤,它將捕捉錯誤、更新狀態並呈現使用者友好的訊息,而不是讓整個應用程式崩潰。

現在,我們將建立一個元件,並將其命名為 Carsection。在 CarSection 元件中,我們將使用 throw new Error 語句在特定條件下生成錯誤。在本例中,如果傳遞給元件的 carName prop 等於 Airbus ,就會觸發錯誤,提示資訊為 not a car

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import React from 'react';
const CarSection = ({carName}) => {
if (carName === 'Airbus') {
throw new Error('not a car')
}
return (
<div >
{carName}
</div>
);
};
export default CarSection;
import React from 'react'; const CarSection = ({carName}) => { if (carName === 'Airbus') { throw new Error('not a car') } return ( <div > {carName} </div> ); }; export default CarSection;
import React from 'react';
const CarSection = ({carName}) => {
if (carName === 'Airbus') {
throw new Error('not a car')
}
return (
<div >
{carName}
</div>
);
};
export default CarSection;

從本質上講, CarSection 元件的設計目的是根據 carName prop 的值有條件地丟擲錯誤,展示瞭如何在 React 應用程式中實現錯誤邊界來管理錯誤。

下一步是在 App.js 元件中使用 ErrorBoundary 元件封裝可能會出錯的元件或程式碼。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import React from "react";
import CarSection from "./CarSection";
import ErrorBoundary from "./ErrorBoundary";
function App() {
return (
<div className="container mx-auto p-4">
<ErrorBoundary>
<CarSection carName={"Toyota"} />
</ErrorBoundary>
<ErrorBoundary>
<CarSection carName={"Honda"} />
</ErrorBoundary>
<ErrorBoundary>
<CarSection carName={"Ford"} />
</ErrorBoundary>
<ErrorBoundary>
<CarSection carName={"Airbus"} />
</ErrorBoundary>
</div>
);
}
export default App;
import React from "react"; import CarSection from "./CarSection"; import ErrorBoundary from "./ErrorBoundary"; function App() { return ( <div className="container mx-auto p-4"> <ErrorBoundary> <CarSection carName={"Toyota"} /> </ErrorBoundary> <ErrorBoundary> <CarSection carName={"Honda"} /> </ErrorBoundary> <ErrorBoundary> <CarSection carName={"Ford"} /> </ErrorBoundary> <ErrorBoundary> <CarSection carName={"Airbus"} /> </ErrorBoundary> </div> ); } export default App;
import React from "react";
import CarSection from "./CarSection";
import ErrorBoundary from "./ErrorBoundary";
function App() {
return (
<div className="container mx-auto p-4">
<ErrorBoundary>
<CarSection carName={"Toyota"} />
</ErrorBoundary>
<ErrorBoundary>
<CarSection carName={"Honda"} />
</ErrorBoundary>
<ErrorBoundary>
<CarSection carName={"Ford"} />
</ErrorBoundary>
<ErrorBoundary>
<CarSection carName={"Airbus"} />
</ErrorBoundary>
</div>
);
}
export default App;

CarSection 元件接收到值為 “Airbus” 的 carName 命題時,它會使用 throw new Error('not a car') 觸發一個錯誤。然後,ErrorBoundary 元件會捕捉到這個錯誤,並顯示其 errorMessage prop 中指定的資訊。在本例中, ErrorBoundary 被設定為顯示 “Not a car” 作為錯誤資訊。因此,當 CarSection 元件接收到 ” Airbus ” 時,使用者介面將顯示 “Not a car” 的錯誤資訊。

"Not a car" 的錯誤資訊

錯誤邊界的侷限性

雖然 React 中的錯誤邊界是處理元件中錯誤的強大工具,但仍有一些限制和注意事項需要了解:

  • 非同步程式碼:非同步程式碼(如 setTimeout 或網路請求)中的錯誤不會被錯誤邊界捕獲,因為它們發生在常規元件生命週期之外。
  • 無法捕捉事件處理程式中的錯誤:錯誤邊界在呈現階段工作,因此不會捕獲事件處理程式或非同步程式碼中出現的錯誤。
  • 錯誤邊界本身中的錯誤:如果錯誤發生在錯誤邊界自身的 rendercomponentDidCatch 或建構函式方法中,錯誤邊界將不會捕獲這些錯誤。這可能會導致錯誤邊界本身失效。
  • 伺服器端渲染: 錯誤邊界不是為捕獲伺服器端渲染過程中發生的錯誤而設計的。它們在客戶端的 React 應用程式中效果最佳。

儘管存在這些侷限性,錯誤邊界仍然是一種有價值的工具,它可以防止崩潰,並在錯誤發生時提供更好的使用者體驗,從而提高應用程式的健壯性。

小結

在本指南中,我們探討了 React 中錯誤邊界的概念,瞭解了它們在類元件的呈現階段和生命週期方法中捕獲錯誤的作用。我們深入研究了它們的用法,設定它們以建立後備使用者介面,並討論了它們的侷限性。

錯誤邊界提供了一種強大的機制,可以防止可怕的白屏宕機,並增強 React 應用程式的彈性。通過在元件層次結構中戰略性地放置錯誤邊界,開發人員可以攔截錯誤、顯示使用者友好的訊息並保持更流暢的使用者體驗。

總之,掌握了錯誤邊界的實現方法,React 開發人員就能建立更強大的應用程式,優雅地處理錯誤,確保更有彈性和使用者友好的網路體驗。

瞭解更多關於 React 錯誤的處理辦法:

評論留言