iT邦幫忙

2024 iThome 鐵人賽

DAY 9
0
Modern Web

React 學得動嗎系列 第 9

[Day 9] React 錯誤邊界:讓你的應用程式不再整個掛掉

  • 分享至 

  • xImage
  •  

哈囉大家好!歡迎來到我們 React 學習之旅的第九天。今天我們要來聊聊一個實用但常常被忽略的功能:錯誤邊界(Error Boundaries)

什麼是錯誤邊界?

如果應用程式是一間大餐廳,每個 React 元件就像是餐廳裡的一個櫃台。錯誤邊界就像是餐廳裡的防火牆,當某個櫃台著火了(發生錯誤),防火牆可以把火侷限在那個區域,不讓整間餐廳都燒起來(整個應用程式當機)。

簡單來說,錯誤邊界是一種特殊的 React 元件,它可以:

  1. 捕捉子元件樹中的 JavaScript 錯誤
  2. 記錄這些錯誤
  3. 顯示一個備用 UI,而不是讓整個元件樹當機

為什麼要用錯誤邊界?

  1. 提升用戶體驗: 當某部分出錯時,不會讓整個應用程式掛掉。
  2. 方便除錯: 可以精確定位哪裡出了問題。
  3. 優雅處理意外狀況: 可以顯示友善的錯誤訊息,而不是一片空白。

如何實作錯誤邊界?

src/components/common/ErrorBoundary.tsx

import React, { Component, ErrorInfo, ReactNode } from 'react';

interface ErrorBoundaryProps {
  children: ReactNode;
  fallback?: ReactNode;
}

interface ErrorBoundaryState {
  hasError: boolean;
}

class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
  constructor(props: ErrorBoundaryProps) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(_: Error): ErrorBoundaryState {
    return { hasError: true };
  }

  componentDidCatch(error: Error, errorInfo: ErrorInfo) {
    console.error('錯誤邊界捕捉到一個錯誤:', error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      return this.props.fallback || <h1>哎呀!好像有東西出錯了。</h1>;
    }

    return this.props.children;
  }
}

export default ErrorBoundary;

這個錯誤邊界元件做了幾件事:

  1. 當子元件拋出錯誤時,它會捕捉這個錯誤。
  2. 它會在 console 中記錄錯誤資訊,方便我們除錯。
  3. 它會顯示一個備用 UI(可以是預設的錯誤訊息,或是傳入的自定義內容)。

如何使用錯誤邊界?

來看看如何在實際應用中使用這個錯誤邊界:

BuggyCounter.tsx

import React from 'react';

// 這是一個會拋出錯誤的元件
const BuggyCounter: React.FC = () => {
    const [count, setCount] = React.useState(0);

    if (count === 3) {
        throw new Error('我數到 3 就會當機啦!');
    }

    return (
        <div>
            <p>數字: {count}</p>
            <button onClick={() => setCount(count + 1)}>
                點我加 1
            </button>
        </div>
    );
};

export default BuggyCounter;

App.tsx

import React from 'react';
import Counter from './components/Counter';
import MessageInput from "@/components/MessageInput.tsx";
import {ThemeProvider} from "@/components/ThemeContext.tsx";
import ThemedButton from "@/components/ThemedButton.tsx";
import ErrorBoundary from "@/components/common/ErrorBoundary.tsx";
import BuggyCounter from "@/components/BuggyCounter.tsx";

const App: React.FC = () => {
    return (
        <ThemeProvider>
        <div className="container mx-auto mt-10">
            <h1 className="text-3xl font-bold mb-6">我的第一個React應用</h1>
            <Counter />
            <MessageInput />
            <ThemedButton />
            <ErrorBoundary fallback={<h2>哎呀!計數器壞掉了。</h2>}>
                <BuggyCounter />
            </ErrorBoundary>
            <hr />
            <ErrorBoundary>
                <h2>這裡很安全,不會受到上面的錯誤影響</h2>
                <BuggyCounter />
            </ErrorBoundary>
        </div>
        </ThemeProvider>

    );
};

export default App;

https://ithelp.ithome.com.tw/upload/images/20240923/20140358wi2TwBuyB2.png

https://ithelp.ithome.com.tw/upload/images/20240923/201403588oAtFAs8yi.png

在這個例子中:

  1. 我們有一個 BuggyCounter 元件,當數到 3 時就會拋出錯誤。
  2. 我們用 ErrorBoundaryBuggyCounter 包起來。
  3. 當錯誤發生時,ErrorBoundary 會顯示我們設定的備用內容。
  4. 注意我們用了兩個 ErrorBoundary,這樣即使一個計數器出錯,另一個還是可以正常運作。

錯誤邊界的注意事項

  1. 錯誤邊界無法捕捉以下類型的錯誤:

    • 事件處理器中的錯誤
    • 非同步程式碼中的錯誤(例如 setTimeoutrequestAnimationFrame 回調函數)
    • 伺服器端渲染時的錯誤
    • 錯誤邊界本身拋出的錯誤
  2. 錯誤邊界在開發模式和生產模式下的行為會有些不同,所以要在兩種模式下都進行測試。

小結

今天我們學習了 React 的錯誤邊界。它就像是應用程式中的安全網,可以防止一個小錯誤演變成大災難。適當地使用錯誤邊界,可以大大提升應用程式的穩定性和用戶體驗。

記住,錯誤邊界不是用來取代 try/catch 的。它們各有用處:try/catch 適合用在知道可能會出錯的特定程式區塊,而錯誤邊界則是用來處理整個子元件樹中未預期的錯誤。

如果你想深入了解錯誤邊界,可以查看 React 官方文檔中關於錯誤邊界的章節


上一篇
[Day 8] React Context:優雅地管理全局狀態
下一篇
[Day 10] React 效能優化:把網站的腿接起來
系列文
React 學得動嗎13
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言