Обработка ошибок: componentDidCatch

Ошибки в компонентах пользовательского интерфейса могут приводить к полной остановке приложения, некорректному отображению интерфейса или нарушению работы других частей приложения. Для их перехвата в Preact используется механизм, схожий с React, через error boundaries и метод жизненного цикла componentDidCatch.


Error Boundary

Error Boundary — это компонент класса, который перехватывает ошибки в своих дочерних компонентах. Такие ошибки могут возникать в следующих случаях:

  • Ошибки во время рендеринга компонента.
  • Ошибки в методах жизненного цикла (кроме конструктора).
  • Ошибки в конструкторах дочерних компонентов.

Компоненты функционального типа напрямую не могут использовать componentDidCatch, поэтому для перехвата ошибок необходим классовый компонент.

Пример базового error boundary:

import { Component, h } from 'preact';

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

  componentDidCatch(error, info) {
    console.error('Ошибка в компоненте:', error);
    console.error('Информация о компоненте:', info);
    this.setState({ hasError: true });
  }

  render() {
    if (this.state.hasError) {
      return <h1>Произошла ошибка.</h1>;
    }
    return this.props.children;
  }
}

export default ErrorBoundary;

Ключевые моменты:

  • componentDidCatch(error, info) получает два аргумента:

    • error — объект ошибки.
    • info — объект с информацией о компоненте (componentStack).
  • После перехвата ошибки состояние компонента обычно обновляется, чтобы отобразить запасной UI.

  • Все дочерние компоненты, обернутые в ErrorBoundary, защищены от остановки приложения.


Использование Error Boundary

Оборачивать error boundary можно вокруг отдельных компонентов или целых разделов приложения:

<ErrorBoundary>
  <MyComplexComponent />
</ErrorBoundary>

Если внутри MyComplexComponent возникнет ошибка во время рендера, приложение не упадет полностью. Вместо этого отобразится сообщение из ErrorBoundary.


Особенности Preact

  • Preact поддерживает componentDidCatch, начиная с версии X (следует проверять актуальную документацию), но не все расширенные возможности React доступны по умолчанию.
  • Для получения полной информации о стеке компонентов иногда требуется подключение дополнительного пакета preact/compat.
  • Обработку ошибок можно комбинировать с логированием на сервер или внешние сервисы (Sentry, LogRocket).

Продвинутая обработка ошибок

Сбор информации для аналитики:

componentDidCatch(error, info) {
  // Локальное логирование
  console.error(error, info);

  // Отправка на сервер
  fetch('/api/log-error', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ error: error.toString(), stack: info.componentStack })
  });

  this.setState({ hasError: true });
}

Динамическое восстановление:

Можно внедрить кнопку “Попробовать снова”, которая сбрасывает состояние error boundary:

render() {
  if (this.state.hasError) {
    return (
      <div>
        <h1>Произошла ошибка.</h1>
        <button onCl ick={() => this.setState({ hasError: false })}>
          Попробовать снова
        </button>
      </div>
    );
  }
  return this.props.children;
}

Ограничения

  • componentDidCatch не ловит ошибки в асинхронных колбэках, обработчиках событий или внутри setTimeout.
  • Для обработки ошибок в промисах и асинхронных функциях рекомендуется использовать .catch() или глобальный обработчик window.onerror.
  • Error boundary не работает с функциональными компонентами напрямую, но их можно оборачивать в классовый компонент.

Рекомендации по применению

  • Разделять приложение на логические блоки и оборачивать критичные компоненты error boundary.
  • Использовать componentDidCatch только для визуального fallback и логирования, не для управления логикой приложения.
  • Для глобальной обработки необработанных ошибок сочетать error boundaries с глобальными обработчиками.

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