切換語言為:簡體

Next.js中如何處理異常?

  • 爱糖宝
  • 2024-09-29
  • 2043
  • 0
  • 0

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元件樹崩潰。但有了錯誤邊界,你就可以將錯誤限制在那個元件內部,並提供一個備用的用戶界面,比如顯示一個錯誤訊息。

錯誤邊界主要依賴兩個生命週期方法:

  1. static getDerivedStateFromError(error):當子元件丟擲錯誤時,這個方法會被呼叫,允許你更新元件的狀態,以便渲染一個備用的用戶界面。

  2. 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中處理異常的方式,希望對你有用。

0則評論

您的電子郵件等資訊不會被公開,以下所有項目均必填

OK! You can skip this field.