Обработка ошибок (Error Boundary)

React Error Boundary — class-компонент, перехватывающий ошибки рендеринга в дочерних компонентах и показывающий fallback вместо белого экрана.

Задача

Ошибка в одном React-компоненте не должна крашить всё приложение. Нужен «предохранитель», который поймает ошибку, залогирует её и покажет пользователю понятное сообщение.

Решение

// components/ErrorBoundary.tsx
import React, { Component, ErrorInfo, ReactNode } from 'react';

interface Props {
  children: ReactNode;
  fallback?: ReactNode;
  onError?: (error: Error, info: ErrorInfo) => void;
}

interface State {
  hasError: boolean;
  error: Error | null;
}

class ErrorBoundary extends Component<Props, State> {
  state: State = { hasError: false, error: null };

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

  componentDidCatch(error: Error, info: ErrorInfo) {
    console.error('ErrorBoundary caught:', error, info.componentStack);
    this.props.onError?.(error, info);
  }

  handleReset = () => {
    this.setState({ hasError: false, error: null });
  };

  render {
    if (this.state.hasError) {
      return (
        this.props.fallback ?? (
          <div className="error-fallback">
            <h2>Что-то пошло не так</h2>
            <p>{this.state.error?.message}</p>
            <button onClick={this.handleReset}>Попробовать снова</button>
          </div>
        )
      );
    }
    return this.props.children;
  }
}

export default ErrorBoundary;

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

import ErrorBoundary from '@/components/ErrorBoundary';

// Обернуть всё приложение
function App() {
  return (
    <ErrorBoundary onError={(err) => logToSentry(err)}>
      <Router />
    </ErrorBoundary>
  );
}

// Обернуть конкретную секцию с кастомным fallback
function Dashboard() {
  return (
    <div>
      <ErrorBoundary fallback={<p>Виджет недоступен</p>}>
        <ChartWidget />
      </ErrorBoundary>
      <ErrorBoundary>
        <TableWidget />
      </ErrorBoundary>
    </div>
  );
}
.error-fallback {
  padding: 24px;
  background: #fef2f2;
  border: 1px solid #fecaca;
  border-radius: 8px;
  text-align: center;
}
.error-fallback h2 { color: #dc2626; margin-bottom: 8px; }
.error-fallback button { margin-top: 12px; padding: 8px 16px; }

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

  • Error Boundary работает только как class-компонент — функциональные компоненты не могут быть Error Boundary (на 2026 год).
  • getDerivedStateFromError — перехватывает ошибку и обновляет state для рендера fallback.
  • componentDidCatch — для логирования (Sentry, DataDog и т.д.); не обновляет state.
  • Error Boundary не ловит: ошибки в обработчиках событий, асинхронные ошибки (fetch), серверные ошибки — только ошибки при рендеринге.

Варианты

  • react-error-boundary — пакет с хуком useErrorBoundary и функциональным API для сброса.
  • Для асинхронных ошибок (fetch) — отдельно обрабатывай в try/catch в хуке и прокидывай состояние.

Связанные рецепты / темы