字
字节笔记本
2026年5月3日
TanStack Start - Error Boundaries 错误边界
API中转
¥120
TanStack Start 基于 TanStack Router 的路由级错误边界系统,提供灵活的错误处理机制。
概述
- 全局默认错误处理: 通过路由器为所有路由设置默认错误组件
- 路由级覆盖: 每个路由可以自定义错误处理
- 错误捕获: 在
beforeLoad、loader中抛出的错误会被自动捕获 - 重试机制: 通过
reset()函数重新渲染路由
全局默认错误组件
在 src/router.tsx 中为所有路由设置默认错误组件:
tsx
import { createRouter, ErrorComponent } from '@tanstack/react-router'
import { routeTree } from './routeTree.gen'
export function getRouter() {
const router = createRouter({
routeTree,
defaultErrorComponent: ({ error, reset }) => (
<ErrorComponent error={error} />
),
})
return router
}路由级错误组件
每个路由可以定义自己的错误组件来覆盖全局默认值:
tsx
import { createFileRoute, ErrorComponent } from '@tanstack/react-router'
function PostError({ error, reset }: ErrorComponentProps) {
return (
<div className="p-4 bg-red-50 rounded-lg">
<h2 className="text-xl font-bold text-red-800">Failed to Load</h2>
<p className="text-red-600 mt-2">{error.message}</p>
<button onClick={reset} className="mt-4 px-4 py-2 bg-red-600 text-white rounded">
Retry
</button>
</div>
)
}
export const Route = createFileRoute('/posts/$postId')({
component: PostComponent,
errorComponent: PostError,
})错误捕获机制
在 Loader 中抛出错误
tsx
export const Route = createFileRoute('/posts/$postId')({
loader: async ({ params }) => {
const post = await fetchPost(params.postId)
if (!post) {
throw new Error('Post not found!')
}
return post
},
errorComponent: PostError,
})在 beforeLoad 中抛出错误
tsx
export const Route = createFileRoute('/admin')({
beforeLoad: async ({ context }) => {
const user = await getCurrentUser()
if (!user.isAdmin) {
throw new Error('Access denied: Admin only')
}
},
errorComponent: AdminError,
})重试机制
reset() 函数允许用户在修复状态后重新渲染路由:
tsx
function PostError({ error, reset }: ErrorComponentProps) {
const handleRetry = () => {
clearCache()
reset()
}
return (
<div>
<h2>Error loading post</h2>
<p>{error.message}</p>
<button onClick={handleRetry}>Retry</button>
</div>
)
}嵌套路由错误处理
在嵌套路由中,错误会冒泡到最近的错误边界:
tsx
// __root.tsx
export const Route = createRootRoute({
component: RootLayout,
errorComponent: RootError, // 捕获所有未处理的错误
})
// dashboard.tsx
export const Route = createFileRoute('/dashboard')({
component: Dashboard,
errorComponent: DashboardError, // 捕获 dashboard 相关错误
})
// dashboard.settings.tsx
export const Route = createFileRoute('/dashboard/settings')({
component: Settings,
// 没有错误组件,错误冒泡到 dashboard 或 root
})错误类型处理
Not Found 错误
tsx
import { notFound } from '@tanstack/react-router'
export const Route = createFileRoute('/posts/$postId')({
loader: async ({ params }) => {
const post = await fetchPost(params.postId)
if (!post) {
throw notFound()
}
return post
},
})重定向错误
tsx
import { redirect } from '@tanstack/react-router'
export const Route = createFileRoute('/protected')({
beforeLoad: async () => {
const isAuthenticated = await checkAuth()
if (!isAuthenticated) {
throw redirect({ to: '/login' })
}
},
})最佳实践
- 提供有用的错误信息 - 不要只显示 error.message
- 提供重试选项 - 使用 reset() 函数
- 开发环境显示堆栈 - 仅在 DEV 模式下显示
- 记录错误 - 发送到错误跟踪服务
API 速查
| API | 位置 | 用途 |
|---|---|---|
defaultErrorComponent | router.tsx | 全局默认错误组件 |
errorComponent | 路由配置 | 路由级错误组件 |
reset() | 错误组件 | 重试渲染路由 |
ErrorComponent | 内置组件 | 简单的错误 UI |
错误处理流程
text
用户操作
│
▼
beforeLoad / loader
│
├─ 成功 → 渲染组件
│
└─ 失败 → 抛出错误
│
▼
路由 errorComponent (如果存在)
│
└─ 不存在 → 冒泡到父路由 errorComponent
│
└─ 最终到达 defaultErrorComponent分享: