錯誤可分為兩類:預期錯誤和未捕獲異常。本頁將指導你如何在 Next.js 應用程序中處理這些錯誤。
預期錯誤是指在應用程序正常運行過程中可能發(fā)生的情況,例如服務器端表單驗證錯誤或請求失敗。這些錯誤應顯式處理并返回給客戶端。
你可以使用 useActionState
鉤子來管理服務器函數(shù)的狀態(tài)并處理預期錯誤。對于預期錯誤,避免使用 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' }
}
}
然后,你可以將操作傳遞給 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">標題</label>
<input type="text" id="title" name="title" required />
<label htmlFor="content">內(nèi)容</label>
<textarea id="content" name="content" required />
{state?.message && <p aria-live="polite">{state.message}</p>}
<button disabled={pending}>創(chuàng)建帖子</button>
</form>
)
}
在服務器組件中獲取數(shù)據(jù)時,可以使用響應來條件渲染錯誤消息或 redirect
。
export default async function Page() {
const res = await fetch(`https://...`)
const data = await res.json()
if (!res.ok) {
return '發(fā)生錯誤'
}
return '...'
}
你可以在路由段中調(diào)用 notFound
函數(shù),并使用 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>
}
export default function NotFound() {
return <div>404 - 未找到頁面</div>
}
未捕獲異常是意料之外的錯誤,表示在應用程序的正常流程中不應發(fā)生的錯誤。這些錯誤應通過拋出錯誤來處理,然后由錯誤邊界捕獲。
Next.js 使用錯誤邊界來處理未捕獲異常。錯誤邊界捕獲子組件中的錯誤,并顯示備用 UI 而不是崩潰的組件樹。
通過在路由段中添加 error.js
文件并導出 React 組件來創(chuàng)建錯誤邊界:
'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>出錯了!</h2>
<button
onClick={
// 嘗試通過重新渲染段來恢復
() => reset()
}
>
重試
</button>
</div>
)
}
錯誤將冒泡到最近的父級錯誤邊界。這允許在路由層次結構的不同級別放置 error.tsx
文件,從而實現(xiàn)細粒度的錯誤處理。
雖然不常見,但你可以在根布局中使用 global-error.js
文件處理錯誤,即使在使用國際化的情況下。全局錯誤 UI 必須定義自己的 <html>
和 <body>
標簽,因為它在活動時會替換根布局或模板。
'use client' // 錯誤邊界必須是客戶端組件
export default function GlobalError({
error,
reset,
}: {
error: Error & { digest?: string }
reset: () => void
}) {
return (
// 全局錯誤必須包含 html 和 body 標簽
<html>
<body>
<h2>出錯了!</h2>
<button onClick={() => reset()}>重試</button>
</body>
</html>
)
}
閱讀 API 參考 ,了解有關本頁中提到的功能的更多信息。
更多建議: