Обработка ошибок навигации

Основные концепции

В TanStack Router навигация управляется через роутеры, которые обеспечивают переходы между состояниями приложения. При этом возможны ситуации, когда переход не может быть выполнен из-за ошибок — например, недоступного ресурса, некорректного URL или проблем с авторизацией. Библиотека предоставляет механизмы для перехвата таких ошибок и управления ими.

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

  • NavigationError — ошибки навигации, возникающие при некорректном переходе или при нарушении условий роутинга.
  • LoaderError — ошибки, возникающие в асинхронных функциях загрузки данных (loader).
  • ActionError — ошибки, которые происходят в действиях (action) при отправке форм или выполнении мутаций данных.

Настройка глобального обработчика ошибок

TanStack Router позволяет определить глобальный обработчик ошибок при создании роутера. Он перехватывает все необработанные ошибки навигации и предоставляет возможность выполнить логирование или перенаправление:

import { createRouter } from '@tanstack/router'

const router = createRouter({
  routeTree,
  onError: (error) => {
    console.error('Ошибка навигации:', error)
    // Пример: перенаправление на страницу ошибки
    if (error instanceof NavigationError) {
      router.navigate({ to: '/error' })
    }
  },
})

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

Обработка ошибок на уровне роутов

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

const usersRoute = {
  path: '/users',
  loader: async () => {
    const response = await fetch('/api/users')
    if (!response.ok) throw new LoaderError('Не удалось загрузить пользователей')
    return response.json()
  },
  errorComponent: ({ error }) => (
    <div>
      <h2>Ошибка загрузки пользователей</h2>
      <p>{error.message}</p>
    </div>
  ),
}

Ключевые моменты:

  • loader может выбрасывать ошибки, которые будут автоматически переданы в errorComponent.
  • errorComponent получает объект ошибки через пропс error.
  • Ошибки можно типизировать, создавая собственные классы ошибок для разных случаев.

Асинхронные ошибки и их управление

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

const postRoute = {
  path: '/posts/:postId',
  loader: async ({ params }) => {
    try {
      const response = await fetch(`/api/posts/${params.postId}`)
      if (!response.ok) throw new LoaderError('Пост не найден')
      return response.json()
    } catch (err) {
      throw new LoaderError(err.message)
    }
  },
  errorComponent: ({ error }) => (
    <div>
      <p>Произошла ошибка: {error.message}</p>
    </div>
  ),
}

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

Перехват ошибок действий (Actions)

Для роутов, обрабатывающих формы и мутации данных, используются функции action. Любые исключения внутри action можно перехватывать и отображать через errorComponent:

const createPostRoute = {
  path: '/create-post',
  action: async ({ formData }) => {
    const response = await fetch('/api/posts', {
      method: 'POST',
      body: formData,
    })
    if (!response.ok) throw new ActionError('Не удалось создать пост')
    return response.json()
  },
  errorComponent: ({ error }) => (
    <div>
      <p>{error.message}</p>
    </div>
  ),
}

Особенности работы с действиями:

  • Ошибки внутри action не останавливают роутер, они перехватываются локально.
  • Можно показывать подробную информацию пользователю, сохраняя возможность повторной отправки данных.
  • Типизация ошибок через собственные классы (ActionError) помогает различать ошибки загрузки и мутаций.

Использование хуков для обработки ошибок

TanStack Router предоставляет хуки, которые позволяют реагировать на изменения состояния ошибок:

  • useRouteError() — получает текущую ошибку роутера в компоненте.
  • useIsFetching() и useIsMutating() — помогают отслеживать состояние асинхронных операций, чтобы показывать индикаторы загрузки и ошибки.

Пример использования useRouteError:

import { useRouteError } from '@tanstack/router'

function ErrorDisplay() {
  const error = useRouteError()
  return (
    <div>
      <h3>Ошибка:</h3>
      <pre>{error.message}</pre>
    </div>
  )
}

Советы по организации обработки ошибок

  1. Разделение уровней ошибок — глобальные ошибки, роутовые ошибки, ошибки действий.
  2. Использование специализированных классов ошибок — облегчает фильтрацию и специфичное поведение.
  3. Локализация ошибок — ошибки конкретного роутера должны обрабатываться внутри него, чтобы пользователь видел контекст.
  4. Логирование и мониторинг — важно не только показывать ошибку пользователю, но и сохранять данные для анализа.

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