useRouteError для доступа к ошибкам

React Router предоставляет мощные механизмы работы с маршрутами и компонентами, в том числе встроенную поддержку обработки ошибок на уровне маршрутов. Хук useRouteError позволяет получать информацию об ошибках, произошедших во время рендеринга маршрута или загрузки данных. Его основная задача — предоставить доступ к объекту ошибки в компоненте-обработчике ошибок (ErrorBoundary) маршрута.

Подключение и использование

useRouteError импортируется из пакета react-router-dom:

import { useRouteError } from "react-router-dom";

Он используется внутри компонента, который назначен свойством errorElement маршрута:

import { useRouteError } from "react-router-dom";

function ErrorPage() {
  const error = useRouteError();
  console.error(error);

  return (
    <div>
      <h1>Произошла ошибка</h1>
      <p>{error.statusText || error.message}</p>
    </div>
  );
}

Привязка к маршруту

Для того чтобы useRouteError корректно работал, необходимо определить маршрут с errorElement:

import { createBrowserRouter, RouterProvider } from "react-router-dom";

const router = createBrowserRouter([
  {
    path: "/",
    element: <MainPage />,
    errorElement: <ErrorPage />,
    children: [
      {
        path: "profile/:id",
        element: <ProfilePage />,
        loader: async ({ params }) => {
          const response = await fetch(`/api/users/${params.id}`);
          if (!response.ok) {
            throw new Response("Не удалось загрузить пользователя", { status: response.status });
          }
          return response.json();
        },
      },
    ],
  },
]);

<RouterProvider router={router} />;

В этом примере, если загрузка данных в loader завершается ошибкой, компонент ErrorPage автоматически получит объект ошибки через useRouteError.

Структура объекта ошибки

useRouteError возвращает объект, который может быть экземпляром Error, Response или пользовательского объекта. Основные поля, которые могут быть полезны:

  • message — текст ошибки (если ошибка была выброшена как Error).
  • status — HTTP-статус (если ошибка представлена как Response).
  • statusText — описание статуса (для Response).
  • Любые другие поля, которые были переданы при создании ошибки.

Пример проверки типа ошибки:

const error = useRouteError();

if (error instanceof Response) {
  return <p>Ошибка загрузки данных: {error.status} {error.statusText}</p>;
} else if (error instanceof Error) {
  return <p>Произошла ошибка: {error.message}</p>;
} else {
  return <p>Неизвестная ошибка</p>;
}

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

useRouteError тесно связан с механизмом loader маршрутов. Любая ошибка, выброшенная внутри loader, автоматически передается в errorElement. Это позволяет централизованно обрабатывать ошибки загрузки данных без необходимости оборачивать каждый fetch в try/catch.

Пример асинхронной обработки:

async function userLoader({ params }) {
  try {
    const response = await fetch(`/api/users/${params.id}`);
    if (!response.ok) {
      throw new Response("Пользователь не найден", { status: 404 });
    }
    return response.json();
  } catch (err) {
    throw new Error("Сбой сети");
  }
}

Если произошла ошибка сети, ErrorPage получит экземпляр Error. Если пользователь не найден, будет передан объект Response.

Каскадное наследование ошибок

React Router поддерживает вложенные маршруты, и useRouteError возвращает ошибку именно текущего маршрута. Ошибки дочернего маршрута не «просачиваются» в родительский, если у родителя определён собственный errorElement. Это позволяет строить точечную обработку ошибок для разных частей приложения.

Пример:

const router = createBrowserRouter([
  {
    path: "/",
    element: <Layout />,
    errorElement: <MainError />,
    children: [
      {
        path: "dashboard",
        element: <Dashboard />,
        errorElement: <DashboardError />,
      },
      {
        path: "settings",
        element: <Settings />,
      },
    ],
  },
]);

В этом случае ошибка в маршруте /dashboard попадёт в DashboardError, а ошибка в маршруте /settings — в MainError.

Рекомендации по использованию

  • Использовать useRouteError только внутри компонентов, назначенных как errorElement. Вне этого контекста он вернёт undefined.
  • Для асинхронных операций всегда использовать throw в loader, чтобы ошибка автоматически передавалась в errorElement.
  • Проверять тип ошибки (Error или Response) для корректного отображения информации пользователю.
  • Можно комбинировать с Outlet для вложенных маршрутов, сохраняя единообразную обработку ошибок в разных уровнях приложения.

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