在 Next.js 應(yīng)用程序中,錯(cuò)誤可分為兩類:預(yù)期錯(cuò)誤和未捕獲異常。本頁(yè)將指導(dǎo)你如何處理這些錯(cuò)誤。
預(yù)期錯(cuò)誤是指在應(yīng)用程序正常運(yùn)行過(guò)程中可能發(fā)生的情況,例如服務(wù)器端表單驗(yàn)證錯(cuò)誤或請(qǐng)求失敗。這些錯(cuò)誤應(yīng)顯式處理并返回給客戶端。
使用 useActionState
鉤子來(lái)管理服務(wù)器操作的狀態(tài),包括處理錯(cuò)誤。這種方法避免了對(duì)預(yù)期錯(cuò)誤使用 try
/catch
塊,而是將錯(cuò)誤建模為返回值,而不是拋出異常。
'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: '請(qǐng)輸入有效的郵箱' }
}
redirect('/dashboard')
}
然后,你可以將操作傳遞給 useActionState
鉤子,并使用返回的 state
顯示錯(cuò)誤消息。
'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">郵箱</label>
<input type="text" id="email" name="email" required />
{/* ... */}
<p aria-live="polite">{state?.message}</p>
<button disabled={pending}>注冊(cè)</button>
</form>
)
}
你也可以使用返回的狀態(tài)從客戶端組件顯示一個(gè)提示消息。
在服務(wù)器組件中獲取數(shù)據(jù)時(shí),可以使用響應(yīng)來(lái)?xiàng)l件渲染錯(cuò)誤消息或 redirect
。
export default async function Page() {
const res = await fetch(`https://...`)
const data = await res.json()
if (!res.ok) {
return '發(fā)生錯(cuò)誤'
}
return '...'
}
未捕獲異常是意料之外的錯(cuò)誤,表示在應(yīng)用程序的正常流程中不應(yīng)發(fā)生的錯(cuò)誤。這些錯(cuò)誤應(yīng)通過(guò)拋出錯(cuò)誤來(lái)處理,然后由錯(cuò)誤邊界捕獲。
Next.js 使用錯(cuò)誤邊界來(lái)處理未捕獲異常。錯(cuò)誤邊界捕獲子組件中的錯(cuò)誤,并顯示備用 UI 而不是崩潰的組件樹。
通過(guò)在路由段中添加 error.tsx
文件并導(dǎo)出 React 組件來(lái)創(chuàng)建錯(cuò)誤邊界:
'use client' // 錯(cuò)誤邊界必須是客戶端組件
import { useEffect } from 'react'
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string }
reset: () => void
}) {
useEffect(() => {
// 將錯(cuò)誤記錄到錯(cuò)誤報(bào)告服務(wù)
console.error(error)
}, [error])
return (
<div>
<h2>出錯(cuò)了!</h2>
<button
onClick={
// 嘗試通過(guò)重新渲染段來(lái)恢復(fù)
() => reset()
}
>
重試
</button>
</div>
)
}
如果你想讓錯(cuò)誤冒泡到父級(jí)錯(cuò)誤邊界,可以在渲染 error
組件時(shí)拋出錯(cuò)誤。
錯(cuò)誤將冒泡到最近的父級(jí)錯(cuò)誤邊界。這允許在路由層次結(jié)構(gòu)的不同級(jí)別放置 error.tsx
文件,從而實(shí)現(xiàn)細(xì)粒度的錯(cuò)誤處理。
雖然不常見(jiàn),但你可以在根布局中使用 app/global-error.js
文件處理錯(cuò)誤,即使在使用國(guó)際化的情況下。全局錯(cuò)誤 UI 必須定義自己的 <html>
和 <body>
標(biāo)簽,因?yàn)樗诨顒?dòng)時(shí)會(huì)替換根布局或模板。
'use client' // 錯(cuò)誤邊界必須是客戶端組件
export default function GlobalError({
error,
reset,
}: {
error: Error & { digest?: string }
reset: () => void
}) {
return (
// 全局錯(cuò)誤必須包含 html 和 body 標(biāo)簽
<html>
<body>
<h2>出錯(cuò)了!</h2>
<button onClick={() => reset()}>重試</button>
</body>
</html>
)
}
更多建議: