Обработка 404 и ошибок
404 — несуществующий маршрут
<Routes>
<Route path="/" element={<Home />} />
<Route path="/posts" element={<Posts />} />
<Route path="*" element={<NotFound />} />
</Routes>
* ловит всё, что не совпало с другими маршрутами.
Компонент 404
function NotFound() {
return (
<div className="not-found">
<h1>404</h1>
<p>Страница не найдена</p>
<Link to="/">На главную</Link>
</div>
);
}
404 внутри раздела
<Route path="/posts" element={<PostsLayout />}>
<Route index element={<PostsList />} />
<Route path=":id" element={<PostDetail />} />
<Route path="*" element={<NotFound />} />
</Route>
URL /posts/unknown/path попадёт в NotFound внутри PostsLayout — с общим сайдбаром.
Ошибки в загрузке данных
function PostDetail() {
const { id } = useParams();
const { data, isLoading, error } = useQuery({
queryKey: ['post', id],
queryFn: () => fetchPost(id!),
});
if (isLoading) return <Spinner />;
if (error) return <ErrorState error={error} />;
if (!data) return <NotFound />;
return <Post post={data} />;
}
ErrorBoundary
React-компонент, который ловит ошибки рендера:
import { Component, ReactNode } from 'react';
class ErrorBoundary extends Component<
{ children: ReactNode; fallback: ReactNode },
{ hasError: boolean }
> {
state = { hasError: false };
static getDerivedStateFromError() {
return { hasError: true };
}
componentDidCatch(error: Error, info: React.ErrorInfo) {
console.error(error, info);
}
render() {
if (this.state.hasError) return this.props.fallback;
return this.props.children;
}
}
Использование:
<ErrorBoundary fallback={<ErrorPage />}>
<App />
</ErrorBoundary>
React Router errorElement
В data router (v6.4+) можно объявить errorElement:
const router = createBrowserRouter([
{
path: '/',
element: <Root />,
errorElement: <ErrorPage />,
children: [
{ path: 'posts', element: <Posts /> },
],
},
]);
Если в маршруте выбросится ошибка — покажется ErrorPage.
useRouteError
import { useRouteError, isRouteErrorResponse } from 'react-router-dom';
function ErrorPage() {
const error = useRouteError();
if (isRouteErrorResponse(error)) {
return (
<>
<h1>{error.status}</h1>
<p>{error.statusText}</p>
</>
);
}
return <h1>Что-то пошло не так</h1>;
}
Логирование
Ошибки нужно логировать на сервер:
componentDidCatch(error: Error, info: React.ErrorInfo) {
fetch('/api/log', {
method: 'POST',
body: JSON.stringify({ message: error.message, stack: info.componentStack }),
});
}
В продакшене — Sentry, LogRocket, Rollbar.
Стратегия
- 404 — для несуществующих путей
- 403 — для доступа без прав
- 500 — ошибка сервера
- ErrorBoundary — ошибки рендера
- Логирование — обязательно
Итоги
path="*"для 404- ErrorBoundary для ошибок рендера
errorElementв data router- Разные страницы для 404 и 500
- Логирование ошибок