В современных SPA-приложениях ошибки навигации или некорректные маршруты могут приводить к неожиданным результатам. React Router предоставляет мощные механизмы для обработки таких ситуаций, позволяя не только корректно отображать страницы ошибок, но и централизованно управлять логикой обработки исключений в маршрутах.
ErrorBoundary и маршрутыВ React Router версии 6+ встроена поддержка компонента
ErrorBoundary, который позволяет обрабатывать ошибки на
уровне маршрутов. Он используется следующим образом:
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import Root from "./Root";
import Home from "./Home";
import NotFound from "./NotFound";
import ErrorPage from "./ErrorPage";
const router = createBrowserRouter([
{
path: "/",
element: <Root />,
errorElement: <ErrorPage />,
children: [
{ path: "/", element: <Home /> },
{ path: "*", element: <NotFound /> },
],
},
]);
function App() {
return <RouterProvider router={router} />;
}
Ключевые моменты:
errorElement привязывается к конкретному маршруту и
отображается при возникновении ошибки в дочерних компонентах.ErrorBoundary для разных
уровней маршрутов, что позволяет более гибко управлять ошибками.*-маршрут используется для обработки “страниц не
найдено”.Компонент, назначенный как errorElement, получает объект
ошибки через хук useRouteError.
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 возвращает объект ошибки, который может
содержать status, statusText,
message и другие свойства, если ошибка связана с загрузкой
данных.React Router поддерживает loader для маршрутов, что
позволяет загружать данные до отображения компонента. Ошибки в
loader автоматически перехватываются
errorElement маршрута.
async function userLoader({ params }) {
const response = await fetch(`/api/users/${params.userId}`);
if (!response.ok) {
throw new Response("Пользователь не найден", { status: 404 });
}
return response.json();
}
const router = createBrowserRouter([
{
path: "/users/:userId",
element: <User />,
loader: userLoader,
errorElement: <UserErrorPage />,
},
]);
Особенности работы:
loader, передается в
errorElement.Response для передачи
статуса HTTP, что позволяет легко строить страницы ошибок типа 404 или
500.Для крупных приложений рекомендуется создавать общий
ErrorBoundary на уровне корневого маршрута. Это позволяет
перехватывать все неожиданные ошибки, которые не были пойманы локальными
обработчиками.
const router = createBrowserRouter([
{
path: "/",
element: <Root />,
errorElement: <GlobalErrorPage />,
children: [
{ path: "dashboard", element: <Dashboard /> },
{ path: "profile", element: <Profile />, errorElement: <ProfileError /> },
{ path: "*", element: <NotFound /> },
],
},
]);
Выводы по структуре:
errorElement дают детальную обработку ошибок
для конкретного маршрута.errorElement служит страховкой от
непредвиденных исключений.Асинхронные компоненты можно сочетать с обработкой ошибок, используя
Suspense и lazy. Если при загрузке компонента
произойдет исключение, оно будет поймано ближайшим
errorElement.
import { lazy, Suspense } from "react";
const LazyComponent = lazy(() => import("./LazyComponent"));
<Route
path="lazy"
element={
<Suspense fallback={<div>Загрузка...</div>}>
<LazyComponent />
</Suspense>
}
errorElement={<LazyErrorPage />}
/>
Примечания:
Suspense отвечает за отображение загрузочного
состояния.errorElement перехватывает исключения, возникшие во
время динамического импорта или рендеринга.Механизмы обработки ошибок в React Router обеспечивают надежную
защиту от неожиданных ситуаций в маршрутах и загрузке данных. Грамотно
организованные ErrorBoundary и errorElement
позволяют создать предсказуемое поведение приложения, повысить
стабильность и улучшить пользовательский опыт.