Гид по технологиям

Обработка ошибок в React с помощью Error Boundaries

• 7 min read • Frontend • Обновлено 30 Nov 2025
Error Boundaries в React: как и где ставить
Error Boundaries в React: как и где ставить

Логотип React на тёмном фоне

Быстрые ссылки

  • Создание границ ошибок
  • Какой метод использовать
  • Где размещать границы ошибок
  • Ограничения границ ошибок
  • Практические рекомендации и сценарии
  • Заключение

Коротко о концепции

Граница ошибок — это компонент, который «обрамляет» часть дерева компонентов и перехватывает JavaScript-ошибки, возникающие глубже по дереву. После перехвата можно отобразить запасной интерфейс (fallback UI) и сохранить видимыми остальные части приложения. Это не замена логированию или мониторингу — скорее средство локализации сбоев.

Важно: термин «граница ошибок» в статье далее будет упоминаться как Error Boundary для ясности.

Создание границ ошибок

Любой класс-компонент React может стать границей ошибок, если реализовать один или оба жизненных метода:

  • componentDidCatch(error, info) — экземплярный метод; вызывается после того, как компонент поймал ошибку. Хорош для отправки данных в систему мониторинга.
  • static getDerivedStateFromError(error) — статический метод; используется для обновления состояния и переключения на запасной UI.

Пример простой границы ошибок (с пояснениями):

class ErrorBoundary extends React.Component {
  state = { error: null };

  static getDerivedStateFromError(error) {
    // Обновляем состояние, чтобы отобразить запасной UI при следующем рендере
    return { error };
  }

  componentDidCatch(error, info) {
    // Можно отправить подробности ошибки в сервис мониторинга
    // logErrorToService(error, info);
  }

  render() {
    if (this.state.error) {
      return 

Произошла ошибка.

; } return this.props.children; } }

Пояснения:

  • getDerivedStateFromError вызывается на фазе рендера и должен вернуть объект состояния.
  • componentDidCatch вызывается на фазе commit (после обновления DOM) и полезен для асинхронного логирования.

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

export const AppRoot = () => (
  
    
      
);

В этом примере отдельная граница вокруг Router защищает навигацию и футер от сбоев в основном контенте.

Какой метод использовать

Оба метода можно определить вместе или по отдельности. Разница — в фазе, на которой они срабатывают:

  • getDerivedStateFromError вызывается во время рендера, до обновления DOM. Это безопаснее для немедленной замены UI.
  • componentDidCatch вызывается после обновления DOM (фаза commit) и подходит для логирования/побочного эффекта.

Практическое правило:

  • используйте getDerivedStateFromError для переключения на запасной интерфейс;
  • используйте componentDidCatch для отправки данных в систему мониторинга.

Важно: componentDidCatch — экземплярный метод, значит он может напрямую вызывать пропсы или методы экземпляра. getDerivedStateFromError статический и возвращает изменения состояния.

Где размещать границы ошибок

Рекомендуется иметь несколько границ ошибок, одну на каждом важном слое интерфейса:

  • глобальная граница вокруг всего приложения (запасной экран на весь экран);
  • границы на уровне маршрутов (чтобы падение контента не ломало шапку/навигацию);
  • границы вокруг сложных виджетов (карты, редакторы, интеграции);
  • при необходимости — мелкие границы вокруг потенциально ненадёжных сторонних компонентов.

Модель расположения:

  • Изолируйте то, что можно восстановить локально (например, секция контента).
  • Не стараетесь оборачивать весь код одной монолитной границей — это нивелирует пользу.

Пример иерархии:


  
// защищает основной контент

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

Ограничения границ ошибок

Границы ошибок полезны, но имеют важные ограничения:

  • Они не перехватывают ошибки в обработчиках событий. Обработчик событие не влияет на цикл рендера, поэтому для них нужны try/catch.
  • Они не ловят ошибки асинхронного кода (например, setTimeout, промисы) — используйте try/catch в async/await и .catch для промисов.
  • Граница ловит только ошибки в компонентах-потомках; ошибки самой границы не будут перехвачены этой же границей.
  • Только класс-компоненты могут быть Error Boundary (на момент написания); функциональные компоненты напрямую не поддерживают роль границы.

Примеры, которые не будут пойманы:


// Исключение в обработчике не будет пойман границей — используйте:
try { /* ... */ } catch (e) { /* ... */ }

Или асинхронный пример:

async function fetchData() {
  const res = await fetch('/api');
  // ошибки здесь нужно ловить .catch или try/catch вокруг await
}

Важно: если хотите, чтобы асинхронная ошибка переводила интерфейс в запасной режим — поймайте её и обновите состояние компонента, который отображает UI.

Практическое руководство и готовые приёмы

Ниже набор практических шаблонов и чеклистов, которые пригодятся при внедрении границ ошибок в проект.

Шпаргалка: какие ошибки ловятся

  • Ловятся: ошибки, брошенные во время рендера, в методах жизненного цикла и в конструкторах потомков.
  • Не ловятся: ошибки в обработчиках событий, в асинхронных колбэках, в сервисных хелперах вне рендера.

Альтернативные подходы

  • Использовать библиотеку типа react-error-boundary (она даёт удобный HOC/Hook-API, но под капотом остаётся класс-компонент).
  • Дополнительно применять глобальное перехватывание ошибок window.onerror и window.onunhandledrejection для логирования и аналитики.

Роль-ориентированные чеклисты

Для разработчика:

  • Реализовать ErrorBoundary с getDerivedStateFromError и componentDidCatch.
  • Отобразить стилизованный запасной UI с элементами навигации или восстановлением.
  • Логировать ошибки с контекстом (props, userId, route).

Для QA:

  • Проверить, что при ошибке в компоненте запасной UI отображается корректно.
  • Убедиться, что не ломается глобальный навбар/футер.
  • Тестировать сценарии асинхронных ошибок и ошибок в обработчиках.

Для менеджера продукта / инженера:

  • Определить критичные зоны приложения для размещения границ.
  • Настроить метрики ошибок и оповещения из componentDidCatch.

Мини-методология быстрого реагирования (playbook)

  1. Локализовать: какая граница поймала ошибку? Собрать stack и context.
  2. Временно откатить релиз/фичу, если ошибка критична.
  3. Восстановить UI: позволить пользователям перейти к другим частям приложения.
  4. Подготовить исправление и тесты, добавить больше границ при необходимости.

Чек-лист для дизайна запасного интерфейса

  • Показывать понятное сообщение (не только «Ошибка»).
  • Дать путь восстановления: «Обновить», «Назад», «Вернуться на главную».
  • Сохранить элементы навигации, если это безопасно.

Ментальные модели и эвристики

  • Модель «капсулируй отказ»: думай о каждой крупной секции как о контейнере, который может аварийно завершиться; цель — не дать отказу распространиться.
  • Эвристика «минимально вредно»: запасной UI должен позволять пользователю выполнить основные задачи (или перейти в безопасное место).
  • Правило «лог — не замена UI»: логирование помогает разработчикам, запасной UI — пользователям.

Решение: когда граница бессильна

  • Если компонент делает побочные эффекты вне рендера (например, напрямую пишет в DOM) и они ломаются — граница может не помочь.
  • Если приложение зависло или браузер выдал критический crash — границы бессильны.

Сниппеты и шаблоны

Быстрая функция для логирования из componentDidCatch:

function logErrorToService(error, info) {
  // Небольшая обёртка для отправки ошибок
  fetch('/log', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ error: error.toString(), info })
  }).catch(() => {/* не мешаем пользователю */});
}

Пример запасного интерфейса с возможностью восстановления:

render() {
  if (this.state.error) {
    return (
      

Что-то пошло не так

Мы уже работаем над этим. Попробуйте вернуться на главную.

); } return this.props.children; }

Диагностическое дерево принятия решений

flowchart TD
  A[Произошла ошибка] --> B{Где ошибка?}
  B -->|В обработчике события| C[Использовать try/catch в обработчике]
  B -->|Асинхронный код| D[Использовать try/catch или .catch для промиса]
  B -->|Во время рендера или в lifecycle потомка| E[Ошибка может быть поймана Error Boundary]
  E --> F{Есть ли граница вокруг компонента?}
  F -->|Да| G[Показать запасной UI + логирование]
  F -->|Нет| H[Ошибка всплывёт и вероятно сломает страницу]

Отладка и тесты

Тесты приёмки должны покрывать:

  • Рендер запасного UI при искусственно брошенном исключении в потомке.
  • Сохранение рабочего состояния соседних компонентов (header/footer).
  • Корректную отправку данных в логи/мониторинг.

Критерии приёмки

  • При ошибке в компоненте отображается понятный запасной интерфейс.
  • Ошибка логируется с контекстом.
  • Ошибка одного маршрута не отключает навигацию и футер.

Частые ошибки внедрения и как их избежать

  1. Обрезать stack trace при логировании — включайте contextual props и current route.
  2. Делать один глобальный ErrorBoundary для всего — лучше иметь несколько гранулярных.
  3. Не тестировать асинхронные сценарии — добавьте unit/e2e для промисов и setTimeout.

Короткий глоссарий

  • Error Boundary — класс-компонент, который перехватывает ошибки в потомках.
  • getDerivedStateFromError — статический метод для переключения состояния на запасной UI.
  • componentDidCatch — метод для побочных эффектов (логирование).

FAQ

Перехватят ли Error Boundaries ошибки в Redux-сайд-эффектах?

Нет: если сайд-эффект выполняется вне фазы рендера (например, в саге или thunk), такие ошибки нужно обрабатывать в самих сайд-эффектах и/или глобальным обработчиком.

Можно ли использовать функциональные компоненты как Error Boundary?

Прямо — нет. На момент написания Error Boundaries реализуются через класс-компоненты. Есть внешние библиотеки, которые дают hook-подобный API, но под капотом всё равно используется класс.

Что показывать пользователю в запасном UI?

Короткое объяснение, возможные действия (обновить, вернуться) и кнопка для перехода в безопасную часть приложения. Не показывайте технические детали ошибки пользователю.

Заключение

Error Boundaries — простой и мощный инструмент для повышения устойчивости интерфейса. Они помогают локализовать сбои, улучшить пользовательский опыт и дают место для сбора диагностики. Проектируйте границы по слоям, логируйте ошибки и не забывайте о сценариях, которые границы не покрывают (обработчики событий и асинхронный код).

Краткие рекомендации для старта:

  • Добавьте глобальную и маршрутные границы в каждое приложение;
  • Используйте getDerivedStateFromError для немедленного переключения UI;
  • Отправляйте логи из componentDidCatch;
  • Тестируйте как синхронные, так и асинхронные ошибки.

–

Социальная превью-подсказка:

  • Заголовок: «Обработка ошибок в React: Error Boundaries»
  • Описание: «Как и где ставить границы ошибок, чтобы изолировать сбои и дать пользователю понятный запасной интерфейс.»
Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Несколько аккаунтов Skype: Multi Skype Launcher
Программное обеспечение

Несколько аккаунтов Skype: Multi Skype Launcher

Журнал для работы: повысить продуктивность
Productivity

Журнал для работы: повысить продуктивность

Персональные звуки уведомлений на Android
Android.

Персональные звуки уведомлений на Android

Скачивание шоу Hulu для офлайн‑просмотра
Стриминг

Скачивание шоу Hulu для офлайн‑просмотра

Microsoft Start: персонализированная новостная лента
Новости

Microsoft Start: персонализированная новостная лента

Как изменить имя в Epic Games быстро
Гайды

Как изменить имя в Epic Games быстро