錯誤處理
錯誤可以分為兩種類別:預期錯誤和未捕獲的例外
- 將預期錯誤建模為回傳值:避免在伺服器動作中對預期錯誤使用
try
/catch
。使用useActionState
來管理這些錯誤並將它們回傳給用戶端。 - 對非預期錯誤使用錯誤邊界:實作使用
error.tsx
和global-error.tsx
檔案的錯誤邊界,以處理非預期錯誤並提供備用 UI。
處理預期錯誤
預期錯誤是在應用程式正常運作期間可能發生的錯誤,例如來自伺服器端表單驗證或失敗請求的錯誤。這些錯誤應明確處理並回傳給用戶端。
處理來自伺服器動作的預期錯誤
使用 useActionState
Hook 來管理伺服器動作的狀態,包括處理錯誤。這種方法避免了對預期錯誤使用 try
/catch
區塊,預期錯誤應建模為回傳值而不是拋出的例外。
app/actions.ts
'use server'
import { redirect } from 'next/navigation'
export async function createUser(prevState: any, formData: FormData) {
const res = await fetch('https://...')
const json = await res.json()
if (!res.ok) {
return { message: 'Please enter a valid email' }
}
redirect('/dashboard')
}
然後,您可以將您的動作傳遞給 useActionState
Hook,並使用回傳的 state
來顯示錯誤訊息。
app/ui/signup.tsx
'use client'
import { useActionState } from 'react'
import { createUser } from '@/app/actions'
const initialState = {
message: '',
}
export function Signup() {
const [state, formAction, pending] = useActionState(createUser, initialState)
return (
<form action={formAction}>
<label htmlFor="email">Email</label>
<input type="text" id="email" name="email" required />
{/* ... */}
<p aria-live="polite">{state?.message}</p>
<button disabled={pending}>Sign up</button>
</form>
)
}
您也可以使用回傳的 state 從用戶端元件顯示 Toast 訊息。
處理來自伺服器元件的預期錯誤
當在伺服器元件內部抓取資料時,您可以使用回應來有條件地渲染錯誤訊息或 redirect
。
app/page.tsx
export default async function Page() {
const res = await fetch(`https://...`)
const data = await res.json()
if (!res.ok) {
return 'There was an error.'
}
return '...'
}
未捕獲的例外
未捕獲的例外是表示錯誤或問題的非預期錯誤,這些錯誤不應在應用程式的正常流程中發生。這些應透過拋出錯誤來處理,然後這些錯誤將被錯誤邊界捕獲。
- 常見: 使用
error.js
處理根版面配置下方的未捕獲錯誤。 - 選用: 使用巢狀
error.js
檔案 (例如app/dashboard/error.js
) 處理細微的未捕獲錯誤 - 不常見: 使用
global-error.js
處理根版面配置中的未捕獲錯誤。
使用錯誤邊界
Next.js 使用錯誤邊界來處理未捕獲的例外。錯誤邊界會捕獲其子元件中的錯誤,並顯示備用 UI,而不是崩潰的元件樹。
透過在路由區段內新增 error.tsx
檔案並匯出 React 元件來建立錯誤邊界
app/dashboard/error.tsx
'use client' // Error boundaries must be Client Components
import { useEffect } from 'react'
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string }
reset: () => void
}) {
useEffect(() => {
// Log the error to an error reporting service
console.error(error)
}, [error])
return (
<div>
<h2>Something went wrong!</h2>
<button
onClick={
// Attempt to recover by trying to re-render the segment
() => reset()
}
>
Try again
</button>
</div>
)
}
如果您希望錯誤冒泡到父錯誤邊界,您可以在渲染 error
元件時 throw
。
處理巢狀路由中的錯誤
錯誤將冒泡到最近的父錯誤邊界。這允許透過將 error.tsx
檔案放置在路由階層中的不同層級來進行細微的錯誤處理。


處理全域錯誤
雖然較不常見,但即使在使用國際化時,您也可以使用位於根應用程式目錄中的 app/global-error.js
來處理根版面配置中的錯誤。全域錯誤 UI 必須定義自己的 <html>
和 <body>
標籤,因為它在啟用時會取代根版面配置或樣板。
app/global-error.tsx
'use client' // Error boundaries must be Client Components
export default function GlobalError({
error,
reset,
}: {
error: Error & { digest?: string }
reset: () => void
}) {
return (
// global-error must include html and body tags
<html>
<body>
<h2>Something went wrong!</h2>
<button onClick={() => reset()}>Try again</button>
</body>
</html>
)
}
這有幫助嗎?