React Router предоставляет мощный механизм для управления навигацией в приложении, но при работе с маршрутизацией могут возникать ошибки, связанные как с самим маршрутом, так и с компонентами, которые он рендерит. Для безопасного и предсказуемого поведения приложения используется концепция Error Boundary.
Error Boundary — это React-компонент, который перехватывает ошибки во время рендеринга, в методах жизненного цикла и в конструкторах дочерних компонентов. Он не перехватывает ошибки в асинхронных колбэках, событиях или серверном рендеринге.
Ключевые методы для реализации:
static getDerivedStateFromError(error) — позволяет
обновить состояние компонента при возникновении ошибки.componentDidCatch(error, info) — используется для
логирования ошибки или отправки её на сервер.Пример базового ErrorBoundary:
import React from 'react';
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false, error: null };
}
static getDerivedStateFromError(error) {
return { hasError: true, error };
}
componentDidCatch(error, info) {
console.error('Ошибка в компоненте:', error);
console.error('Информация о стеке:', info);
}
render() {
if (this.state.hasError) {
return <h1>Произошла ошибка: {this.state.error.message}</h1>;
}
return this.props.children;
}
}
export default ErrorBoundary;
В React Router (версии 6 и выше) появилась возможность интегрировать
ErrorBoundary непосредственно в маршруты через свойство
errorElement. Это позволяет каждому маршруту обрабатывать
собственные ошибки независимо, без необходимости оборачивать весь роутер
одним глобальным ErrorBoundary.
Пример использования:
import { createBrowserRouter, RouterProvider, Route } from 'react-router-dom';
import ErrorBoundary from './ErrorBoundary';
import HomePage from './HomePage';
import AboutPage from './AboutPage';
import ProfilePage from './ProfilePage';
const router = createBrowserRouter([
{
path: '/',
element: <HomePage />,
errorElement: <ErrorBoundary />,
},
{
path: '/about',
element: <AboutPage />,
errorElement: <ErrorBoundary />,
},
{
path: '/profile/:id',
element: <ProfilePage />,
errorElement: <ErrorBoundary />,
},
]);
function App() {
return <RouterProvider router={router} />;
}
В этом примере каждая страница имеет собственный ErrorBoundary, что обеспечивает локализованное управление ошибками.
React Router активно использует loader,
action и defer, которые могут
возвращать ошибки асинхронно. Чтобы обработать такие ошибки, можно
использовать useRouteError внутри компонента ErrorBoundary,
указанного в errorElement.
Пример:
import { useRouteError } from 'react-router-dom';
function RouteError() {
const error = useRouteError();
console.error('Ошибка маршрута:', error);
return (
<div>
<h2>Не удалось загрузить страницу</h2>
<p>{error.statusText || error.message}</p>
</div>
);
}
Ошибка в компоненте: если HomePage выбрасывает исключение во время рендеринга, ErrorBoundary перехватит её и отобразит пользовательское сообщение.
Ошибка загрузки данных (loader): при сбое в
асинхронной загрузке данных для маршрута /profile/:id
компонент RouteError получит объект ошибки с status и
statusText.
Ошибка действия (action): при отправке формы на
маршруте /about и выбросе ошибки внутри action,
соответствующий errorElement отобразит сообщение об
ошибке.
errorElement. Подход полезен, когда разные
страницы требуют разной обработки ошибок.<RouterProvider> или <Routes> и
обеспечивают единую обработку всех ошибок.Пример глобального ErrorBoundary:
function App() {
return (
<ErrorBoundary>
<RouterProvider router={router} />
</ErrorBoundary>
);
}
Комбинация локальных и глобальных ErrorBoundary позволяет контролировать и ошибки маршрутов, и ошибки на уровне всего приложения.
errorElement для маршрутов, которые
загружают данные асинхронно.Suspense и состояния загрузки внутри
компонентов.React Router совместно с ErrorBoundary обеспечивает безопасную маршрутизацию и повышает стабильность приложения, позволяя гибко управлять ошибками как на уровне отдельных страниц, так и глобально.