Основные концепции обработки ошибок
В TanStack Router обработка ошибок при загрузке данных (loaders) реализуется через Error Boundaries. Ошибки, возникающие в асинхронных функциях загрузки, автоматически передаются в соответствующий error boundary, если он определён в маршруте. Это позволяет изолировать ошибки на уровне маршрутов и отображать пользователю информативные сообщения без падения всего приложения.
Error boundary можно задать двумя способами:
import { Router, Route } from '@tanstack/router'
const router = new Router({
routeTree: Route({
path: '/',
component: RootComponent,
errorComponent: RootErrorComponent,
children: [
Route({
path: 'dashboard',
component: Dashboard,
loader: async () => {
const data = await fetchDashboardData()
if (!data) throw new Error('Ошибка загрузки данных панели')
return data
},
errorComponent: DashboardErrorComponent,
}),
],
}),
})
В этом примере DashboardErrorComponent будет вызван
только при ошибках загрузки dashboard, тогда как
RootErrorComponent перехватывает ошибки на уровне
родителя.
Все функции загрузки в TanStack Router являются асинхронными. Любая
ошибка, выброшенная в loader, автоматически передается в
error boundary маршрута. Для управления состоянием ошибки часто
используют стандартный объект ошибки Error или собственные
классы ошибок.
class NotFoundError extends Error {}
class UnauthorizedError extends Error {}
const loader = async () => {
const response = await fetch('/api/user')
if (response.status === 404) throw new NotFoundError('Пользователь не найден')
if (response.status === 401) throw new UnauthorizedError('Не авторизован')
return response.json()
}
В errorComponent можно использовать проверку типа ошибки
для отображения различных сообщений пользователю:
function UserError({ error }) {
if (error instanceof NotFoundError) {
return <div>Пользователь не найден</div>
}
if (error instanceof UnauthorizedError) {
return <div>Доступ запрещён</div>
}
return <div>Произошла непредвиденная ошибка</div>
}
TanStack Router поддерживает вложенные маршруты с наследованием error
boundaries. Если дочерний маршрут не определяет
errorComponent, ошибка поднимается к родительскому
маршруту. Это позволяет создавать централизованную обработку ошибок для
группы маршрутов.
const router = new Router({
routeTree: Route({
path: '/',
component: App,
errorComponent: AppError,
children: [
Route({
path: 'profile',
component: Profile,
loader: fetchProfile,
}),
Route({
path: 'settings',
component: Settings,
loader: fetchSettings,
}),
],
}),
})
Если fetchProfile или fetchSettings
выбросит ошибку, и ни один дочерний маршрут не имеет
errorComponent, будет вызван AppError.
Для улучшения UX часто необходимо отображать загрузку и ошибки одновременно. TanStack Router предоставляет хуки для получения текущего состояния загрузки и ошибки маршрута:
useLoaderData() — данные после успешной загрузкиuseRouteError() — объект ошибки текущего маршрутаuseIsFetching() — индикатор активных загрузокПример комбинированного использования:
function ProfilePage() {
const data = useLoaderData()
const error = useRouteError()
const isFetching = useIsFetching()
if (error) return <ProfileError error={error} />
if (isFetching) return <div>Загрузка...</div>
return <ProfileDetails data={data} />
}
Для минимизации критических сбоев рекомендуется:
const router = new Router({
routeTree: Route({
path: '/',
component: App,
errorComponent: AppError,
children: [
Route({
path: 'dashboard',
component: Dashboard,
loader: fetchDashboardData,
errorComponent: DashboardError,
children: [
Route({
path: 'stats',
component: Stats,
loader: fetchStats,
}),
],
}),
],
}),
})
fetchStats → если нет StatsError,
будет вызван DashboardError.fetchDashboardData → вызов
DashboardError./ → вызов
AppError.Эта каскадная модель позволяет изолировать ошибки, сохраняя удобство пользовательского интерфейса.