Next.js 載入中與錯誤處理

在現代網頁應用中,使用者體驗 (UX) 的關鍵在於「即時回饋」。當使用者點擊連結後,系統不應該毫無反應。Next.js 透過內建的 loading.tsxerror.tsx 檔案慣例,讓你能輕鬆處理這些狀態。

載入中狀態 (Loading UI)

loading.tsx 檔案利用了 React 的 Suspense 機制,當該路由的內容(Server Components)正在擷取數據時,會自動顯示此 UI。

為什麼這很重要?

  • 即時回饋:導航時會立即切換到 Loading 畫面。
  • 共享 Layout:當 Loading 顯示時,導航欄等共享 UI 依然是可互動的。

實作範例:

只需在路由資料夾下建立 loading.tsx

// app/dashboard/loading.tsx
export default function Loading() {
  // 你可以使用 Tailwind CSS 畫一個簡單的 Skeleton 畫面
  return (
    <div className="flex items-center justify-center min-h-[200px]">
      <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-500"></div>
      <p className="ml-4 text-gray-500 font-medium">資料載入中,請稍候...</p>
    </div>
  );
}

錯誤處理 (Error Handling)

error.tsx 檔案利用了 Error Boundary 機制。它會攔截子組件中發生的非預期運行錯誤,並顯示一個備用的 UI,而不是讓整個網站崩潰 (Crash)。

實作範例:

// app/dashboard/error.tsx
'use client'; // Error Components 必須是 Client Components

import { useEffect } from 'react';

export default function Error({
  error,
  reset,
}: {
  error: Error & { digest?: string };
  reset: () => void;
}) {
  useEffect(() => {
    // 你可以將錯誤記錄到 Sentry 等監控服務
    console.error(error);
  }, [error]);

  return (
    <div className="p-8 text-center bg-red-50 rounded-lg border border-red-200">
      <h2 className="text-xl font-bold text-red-600 mb-2">發生了非預期錯誤!</h2>
      <p className="text-red-500 mb-4">{error.message || '請聯繫管理員。'}</p>
      <button
        onClick={() => reset()} // 嘗試重新渲染該路由
        className="px-6 py-2 bg-red-600 text-white font-semibold rounded-md hover:bg-red-700 transition"
      >
        嘗試重新載入
      </button>
    </div>
  );
}
error.tsx 只會捕獲該分段及其子分段的錯誤。如果 layout.tsx 中發生錯誤,則由父級的 error.tsx 捕獲。

處理 404 (Not Found)

當某個路由不存在,或是你在程式中主動確認該資源不存在時,可以使用 not-found.tsx

主動呼叫範例:

// app/users/[id]/page.tsx
import { notFound } from 'next/navigation';

export default async function UserProfile({ params }: { params: { id: string } }) {
  const user = await fetchUser(params.id);

  if (!user) {
    // 當資料庫查無此人時,主動觸發 404
    notFound();
  }

  return <div>Hello, {user.name}</div>;
}

小結

透過這些內建檔案,你不需要手動控制每個頁面的 isLoadingerror 狀態:

  • loading.tsx:負責數據加載期間的視覺。
  • error.tsx:負責發生崩潰時的復原。
  • not-found.tsx:負責處理不存在的資源。

這套機制讓你的核心程式碼更乾淨,同時確保了極高的穩定性。