Логирование ошибок маршрутизации

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

Использование компонента <ErrorBoundary>

React Router версии 6 и выше поддерживает интеграцию с React Error Boundaries. Это позволяет обрабатывать ошибки внутри отдельных маршрутов и централизованно логировать их. Основные моменты работы с Error Boundary:

import { Component } from "react";

class RouteErrorBoundary extends Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    return { hasError: true };
  }

  componentDidCatch(error, errorInfo) {
    console.error("Ошибка маршрутизации:", error);
    console.error("Дополнительная информация:", errorInfo);
  }

  render() {
    if (this.state.hasError) {
      return <h1>Произошла ошибка при загрузке страницы.</h1>;
    }

    return this.props.children;
  }
}

Использование Error Boundary с маршрутом:

import { BrowserRouter, Routes, Route } from "react-router-dom";
import HomePage from "./HomePage";
import ProfilePage from "./ProfilePage";

<BrowserRouter>
  <Routes>
    <Route
      path="/"
      element={
        <RouteErrorBoundary>
          <HomePage />
        </RouteErrorBoundary>
      }
    />
    <Route
      path="/profile"
      element={
        <RouteErrorBoundary>
          <ProfilePage />
        </RouteErrorBoundary>
      }
    />
  </Routes>
</BrowserRouter>

Перехват ошибок динамических маршрутов

При использовании React.lazy для динамической загрузки компонентов необходимо оборачивать их в Suspense и Error Boundary для корректного логирования ошибок загрузки:

import { Suspense, lazy } from "react";

const LazyComponent = lazy(() => import("./LazyComponent"));

<Route
  path="/lazy"
  element={
    <RouteErrorBoundary>
      <Suspense fallback={<div>Загрузка...</div>}>
        <LazyComponent />
      </Suspense>
    </RouteErrorBoundary>
  }
/>

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

Логирование с использованием глобального обработчика ошибок

Для отслеживания неожиданных ошибок маршрутизации можно использовать глобальный обработчик window.onerror или window.addEventListener('unhandledrejection'):

window.oner ror = (message, source, lineno, colno, error) => {
  console.error("Глобальная ошибка маршрутизации:", message, error);
};

window.addEventListener("unhandledrejection", (event) => {
  console.error("Необработанное Promise-отклонение:", event.reason);
});

Такая схема позволяет фиксировать ошибки, которые не были пойманы на уровне компонентов.

Настройка логирования через внешние сервисы

Для производственных приложений критически важно отправлять ошибки маршрутизации на внешние системы мониторинга, такие как Sentry или LogRocket:

import * as Sentry from "@sentry/react";

class RouteErrorBoundaryWithSentry extends Component {
  componentDidCatch(error, errorInfo) {
    Sentry.captureException(error, { extra: errorInfo });
  }

  render() {
    return this.props.children;
  }
}

Это обеспечивает централизованное хранение информации о сбоях и позволяет анализировать повторяющиеся ошибки на различных страницах приложения.

Обработка ошибок при переходе по маршрутам

React Router предоставляет хук useNavigate для программной навигации. Ошибки при вызове navigate также можно логировать:

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

function SomeComponent() {
  const navigate = useNavigate();

  const handleNavigation = () => {
    try {
      navigate("/non-existent-route");
    } catch (error) {
      console.error("Ошибка перехода:", error);
    }
  };

  return <button onCl ick={handleNavigation}>Перейти</button>;
}

Использование useRouteError в маршрутах с обработкой ошибок

React Router v6.4+ поддерживает маршруты с конфигурацией errorElement, где можно использовать хук useRouteError:

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

function ErrorPage() {
  const error = useRouteError();
  console.error("Ошибка маршрута:", error);
  return <div>Произошла ошибка при отображении страницы.</div>;
}

<Routes>
  <Route path="/dashboard" element={<Dashboard />} errorElement={<ErrorPage />} />
</Routes>

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

Практические рекомендации

  • Использовать Error Boundary для каждого крупного маршрута или группы маршрутов.
  • Логировать ошибки в консоль в режиме разработки, отправлять на внешние сервисы в продакшне.
  • Для динамических компонентов оборачивать Suspense и Error Boundary.
  • Разграничивать локальные ошибки компонентов и глобальные ошибки приложения.
  • Использовать хук useRouteError для маршрутов, требующих отдельного отображения ошибок.

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