錯誤處理指南

錯誤可分為兩類:預期錯誤未捕獲異常。本頁將引導您如何在 Next.js 應用程式中處理這些錯誤。

處理預期錯誤

預期錯誤是指在應用程式正常運行期間可能發生的錯誤,例如來自伺服器端表單驗證或失敗的請求。這些錯誤應明確處理並返回給客戶端。

伺服器函式

您可以使用 useActionState 鉤子來處理伺服器函式中的預期錯誤。

對於這些錯誤,請避免使用 try/catch 區塊和拋出錯誤。相反,將預期錯誤建模為返回值。

'use server'

export async function createPost(prevState: any, formData: FormData) {
  const title = formData.get('title')
  const content = formData.get('content')

  const res = await fetch('https://api.vercel.app/posts', {
    method: 'POST',
    body: { title, content },
  })
  const json = await res.json()

  if (!res.ok) {
    return { message: 'Failed to create post' }
  }
}

您可以將您的 action 傳遞給 useActionState 鉤子,並使用返回的 state 來顯示錯誤訊息。

'use client'

import { useActionState } from 'react'
import { createPost } from '@/app/actions'

const initialState = {
  message: '',
}

export function Form() {
  const [state, formAction, pending] = useActionState(createPost, initialState)

  return (
    <form action={formAction}>
      <label htmlFor="title">Title</label>
      <input type="text" id="title" name="title" required />
      <label htmlFor="content">Content</label>
      <textarea id="content" name="content" required />
      {state?.message && <p aria-live="polite">{state.message}</p>}
      <button disabled={pending}>Create Post</button>
    </form>
  )
}

伺服器元件

在伺服器元件中獲取資料時,您可以使用回應來有條件地渲染錯誤訊息或執行 redirect

export default async function Page() {
  const res = await fetch(`https://...`)
  const data = await res.json()

  if (!res.ok) {
    return 'There was an error.'
  }

  return '...'
}

找不到頁面

您可以在路由段中呼叫 notFound 函式,並使用 not-found.js 檔案來顯示 404 UI。

import { getPostBySlug } from '@/lib/posts'

export default async function Page({ params }: { params: { slug: string } }) {
  const { slug } = await params
  const post = getPostBySlug(slug)

  if (!post) {
    notFound()
  }

  return <div>{post.title}</div>
}

處理未捕獲異常

未捕獲異常是指不應在應用程式正常流程中發生的意外錯誤,這些錯誤表示存在錯誤或問題。這些錯誤應透過拋出錯誤來處理,然後由錯誤邊界捕獲。

嵌套錯誤邊界

Next.js 使用錯誤邊界來處理未捕獲的異常。錯誤邊界會捕獲其子元件中的錯誤,並顯示後備 UI 而不是崩潰的元件樹。

透過在路由段內添加 error.js 檔案並導出 React 元件來創建錯誤邊界:

'use client' // 錯誤邊界必須是客戶端元件

import { useEffect } from 'react'

export default function Error({
  error,
  reset,
}: {
  error: Error & { digest?: string }
  reset: () => void
}) {
  useEffect(() => {
    // 將錯誤記錄到錯誤報告服務
    console.error(error)
  }, [error])

  return (
    <div>
      <h2>Something went wrong!</h2>
      <button
        onClick={
          // 嘗試透過重新渲染該段來恢復
          () => reset()
        }
      >
        Try again
      </button>
    </div>
  )
}

錯誤會冒泡到最近的父級錯誤邊界。這允許透過在路由層次結構的不同級別放置 error.tsx 檔案來進行細粒度的錯誤處理。

嵌套錯誤元件層次結構

全域錯誤

雖然較不常見,但您可以使用位於根應用目錄中的 global-error.js 檔案來處理根佈局中的錯誤,即使在使用國際化時也是如此。全域錯誤 UI 必須定義自己的 <html><body> 標籤,因為它在活動時會替換根佈局或模板。

'use client' // 錯誤邊界必須是客戶端元件

export default function GlobalError({
  error,
  reset,
}: {
  error: Error & { digest?: string }
  reset: () => void
}) {
  return (
    // global-error 必須包含 html 和 body 標籤
    <html>
      <body>
        <h2>Something went wrong!</h2>
        <button onClick={() => reset()}>Try again</button>
      </body>
    </html>
  )
}

On this page