Компонент errorElement

В React Router начиная с версии 6 введена концепция errorElement, которая позволяет централизованно обрабатывать ошибки, возникающие на уровне маршрутов. Этот компонент выступает аналогом классических обработчиков ошибок в других фреймворках и обеспечивает гибкое управление отображением ошибок при навигации, загрузке данных или рендеринге компонентов.


Основная идея

errorElement используется в объекте маршрута (RouteObject) и представляет собой React-компонент, который будет рендериться при возникновении ошибок внутри соответствующего маршрута. Ошибки могут быть двух типов:

  1. Ошибки загрузки данных: выбрасываются функциями loader маршрута.
  2. Ошибки рендеринга: возникающие внутри компонентов маршрута.

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

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

function Root() {
  return <h1>Главная страница</h1>;
}

function ErrorPage({ error }) {
  return (
    <div>
      <h2>Произошла ошибка!</h2>
      <p>{error.message}</p>
    </div>
  );
}

const router = createBrowserRouter([
  {
    path: "/",
    element: <Root />,
    errorElement: <ErrorPage />,
  },
]);

function App() {
  return <RouterProvider router={router} />;
}

В этом примере компонент ErrorPage автоматически отображается, если любой код маршрута / выбросит исключение.


Передача информации об ошибке

Компонент errorElement получает специальный объект через хук useRouteError(). Он содержит информацию о возникшей ошибке:

  • status — HTTP-статус ошибки (если она была выброшена в loader или action).
  • statusText — описание статуса.
  • message — текст ошибки, если он был передан при выбросе.
  • stack — стек вызовов для отладки (не рекомендуется показывать пользователям в продакшн).

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

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

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

  return (
    <div>
      <h1>Ошибка {error.status || "неизвестная"}</h1>
      <p>{error.statusText || error.message}</p>
    </div>
  );
}

Ошибки загрузки данных (loader) и действий (action)

loader и action могут выбрасывать объекты Response, ошибки или строки. React Router автоматически передаст их в errorElement. Например:

async function loader() {
  const response = await fetch("/api/data");
  if (!response.ok) {
    throw new Response("Данные не найдены", { status: 404 });
  }
  return response.json();
}

Если loader выбрасывает Response, компонент errorElement сможет получить статус через error.status и текст через error.statusText.


Вложенные маршруты и наследование errorElement

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

Пример вложенной структуры:

const router = createBrowserRouter([
  {
    path: "/",
    element: <Root />,
    errorElement: <RootError />,
    children: [
      {
        path: "dashboard",
        element: <Dashboard />,
        errorElement: <DashboardError />,
      },
    ],
  },
]);
  • Ошибка в Dashboard отобразит DashboardError.
  • Ошибка в Root (например, в Root.loader) отобразит RootError.
  • Если DashboardError отсутствует, будет показан RootError.

Управление стилями и пользовательским интерфейсом

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

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

  return (
    <div style={{ padding: "2rem", textAlign: "center" }}>
      <h1>Упс!</h1>
      <p>{error.status ? `Код: ${error.status}` : error.message}</p>
      <button onCl ick={() => window.history.back()}>Назад</button>
    </div>
  );
}

Особенности обработки ошибок

  • Ошибки в loader и action обрабатываются синхронно и асинхронно одинаково.
  • Исключения внутри самого React-компонента маршрута (element) обрабатываются через ErrorBoundary, который React Router реализует под капотом.
  • errorElement работает только для ошибок внутри маршрута; глобальные ошибки вне маршрутов требуют отдельного управления.

Примеры продвинутых сценариев

1. Динамические ошибки на основе статуса:

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

  if (error.status === 404) {
    return <p>Страница не найдена</p>;
  } else if (error.status === 500) {
    return <p>Внутренняя ошибка сервера</p>;
  }
  return <p>Произошла неизвестная ошибка</p>;
}

2. Обработка ошибок с возможностью повторной загрузки данных:

function ErrorPage() {
  const error = useRouteError();
  const navigate = useNavigate();

  return (
    <div>
      <p>{error.message}</p>
      <button onCl ick={() => navigate(0)}>Попробовать снова</button>
    </div>
  );
}

Использование errorElement делает структуру маршрутов более устойчивой к ошибкам и позволяет создавать единообразные страницы ошибок без дублирования логики во всех компонентах. В сочетании с loader и action это обеспечивает мощный механизм обработки ошибок на уровне маршрутов.