Восстановление после ошибок

В TanStack Router обработка ошибок и восстановление после них строится вокруг концепции error boundaries. Ошибки могут возникать как на уровне загрузки данных (loader), действий (action), так и в компонентах маршрутов. Понимание того, как библиотека структурирует обработку ошибок, позволяет создавать устойчивые приложения и предотвращать падение всей страницы при локальных сбоях.

Error Boundary в маршрутах

Каждый маршрут может иметь собственный errorElement. Это компонент, который будет рендериться в случае ошибки в этом маршруте или его потомках:

import { Router, Route } from '@tanstack/router'

const ErrorPage = ({ error }) => (
  <div>
    <h1>Произошла ошибка</h1>
    <pre>{error.message}</pre>
  </div>
)

const router = new Router({
  routeTree: Route({
    path: '/',
    component: HomePage,
    errorElement: ErrorPage,
    children: [
      Route({
        path: 'profile',
        component: ProfilePage,
      }),
    ],
  }),
})

Ключевой момент: ошибка в дочернем маршруте пробрасывается вверх к ближайшему errorElement, а не ломает весь роутер.

Асинхронные ошибки в loader и action

TanStack Router активно использует загрузчики данных и действия. Любая ошибка в этих функциях автоматически прокидывается в соответствующий errorElement.

const profileLoader = async () => {
  const response = await fetch('/api/profile')
  if (!response.ok) {
    throw new Error('Не удалось загрузить профиль')
  }
  return response.json()
}

const profileRoute = Route({
  path: '/profile',
  component: ProfilePage,
  loader: profileLoader,
  errorElement: ProfileError,
})

Важные аспекты:

  • Ошибка в loader не вызывает повторного рендеринга компонента маршрута. Вместо этого рендерится errorElement.
  • Ошибка в action (например, при отправке формы) ведет себя аналогично — можно показывать локальные уведомления об ошибке, не ломая страницу.

Восстановление после ошибки

В TanStack Router можно вернуть приложение в стабильное состояние после ошибки без полной перезагрузки. Для этого применяются несколько подходов:

  1. Использование useResetErrorBoundary Хук позволяет программно сбросить состояние ошибки и заново попытаться загрузить маршрут:
import { useResetErrorBoundary } from '@tanstack/router'

function ErrorPage({ error }) {
  const reset = useResetErrorBoundary()
  return (
    <div>
      <p>Произошла ошибка: {error.message}</p>
      <button onCl ick={reset}>Попробовать снова</button>
    </div>
  )
}
  1. Автоматическое восстановление после изменения пути Перемещение пользователя на другой маршрут автоматически сбрасывает ошибку, что предотвращает зависание errorElement.

  2. Комбинация с Suspense и загрузкой данных Можно объединять errorElement с <Suspense> для асинхронного рендеринга компонентов, создавая плавное восстановление после ошибок загрузки:

<Suspense fallback={<Loading />}>
  <RouteComponent />
</Suspense>

Если загрузка завершилась ошибкой, сработает ближайший errorElement.

Локальная обработка ошибок в компонентах

Даже при использовании loader и action иногда требуется перехватывать ошибки внутри компонентов. Для этого TanStack Router позволяет комбинировать стандартные React error boundaries с маршрутизатором:

class ComponentBoundary extends React.Component {
  state = { hasError: false, error: null }

  static getDerivedStateFromError(error) {
    return { hasError: true, error }
  }

  render() {
    if (this.state.hasError) {
      return <div>Ошибка в компоненте: {this.state.error.message}</div>
    }
    return this.props.children
  }
}

<Route path="/settings" component={() => (
  <ComponentBoundary>
    <SettingsPage />
  </ComponentBoundary>
)} />

Этот подход полезен для локальных ошибок, которые не связаны с загрузкой данных маршрута.

Советы по проектированию ошибок

  • Всегда предоставлять информативный errorElement, чтобы пользователь понимал, что произошло.
  • Разделять ошибки загрузки данных и ошибки UI, чтобы легче восстанавливаться.
  • Использовать useResetErrorBoundary или изменение маршрута для восстановления без полной перезагрузки страницы.
  • Локализовать обработку ошибок на уровне маршрута, чтобы сбой одного участка приложения не ломал весь интерфейс.

Итоговая структура восстановления

  1. Ошибка возникает в loader, action или компоненте.
  2. TanStack Router ищет ближайший errorElement.
  3. errorElement рендерится, предотвращая падение всего приложения.
  4. Для восстановления используются кнопки, хук useResetErrorBoundary или переход на другой маршрут.
  5. После восстановления маршрута данные заново загружаются через loader.

Эта архитектура обеспечивает гибкое, модульное и безопасное управление ошибками, сохраняя стабильность приложения и улучшая пользовательский опыт.