← Назад к вопросам

Делал ли обертку для отлова ошибок в React

2.0 Middle🔥 202 комментариев
#React#Архитектура и паттерны

Комментарии (2)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Делал ли обертку для отлова ошибок в React

Да, error boundaries — это стандартный паттерн в React для обработки ошибок в компонентах. Это специальные компоненты класса, которые ловят ошибки, произошедшие в дочерних компонентах, и отображают fallback UI вместо белого экрана смерти.

Что такое Error Boundary

Error Boundary — это компонент класса, который использует lifecycle методы componentDidCatch() и getDerivedStateFromError() для обработки ошибок в дереве дочерних компонентов.

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

  // Обновляет state при ошибке
  static getDerivedStateFromError(error) {
    return { hasError: true, error };
  }

  // Логирует ошибку (например, в сервис мониторинга)
  componentDidCatch(error, errorInfo) {
    console.error('Ошибка в компоненте:', error);
    console.error('Стек вызовов:', errorInfo.componentStack);
    
    // Отправляем в Sentry, DataDog и т.д.
    logErrorToService(error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      return (
        <div className="error-container">
          <h1>Что-то пошло не так</h1>
          <p>{this.state.error?.message}</p>
          <button onClick={() => window.location.reload()}>
            Перезагрузить страницу
          </button>
        </div>
      );
    }

    return this.props.children;
  }
}

// Использование
export function App() {
  return (
    <ErrorBoundary>
      <Header />
      <MainContent />
      <Footer />
    </ErrorBoundary>
  );
}

Когда Error Boundary ловит ошибки

Error Boundary ловит:

  • Ошибки в render методе
  • Ошибки в lifecycle методах
  • Ошибки в конструкторах дочерних компонентов
  • Ошибки в useEffect хуках (React 18+)

Error Boundary НЕ ловит:

  • Асинхронные ошибки (setTimeout, Promise.catch)
  • Обработчики событий (onClick, onChange)
  • Ошибки в самом Error Boundary компоненте

Практический пример с несколькими boundaries

// Общая Error Boundary для всего приложения
class GlobalErrorBoundary extends React.Component {
  componentDidCatch(error, errorInfo) {
    // Отправляем критичные ошибки в мониторинг
    reportError(error, { severity: 'critical', ...errorInfo });
  }

  render() {
    if (this.state.hasError) {
      return <CriticalErrorPage />;
    }
    return this.props.children;
  }
}

// Локальная Error Boundary для конкретного раздела
class SectionErrorBoundary extends React.Component {
  render() {
    if (this.state.hasError) {
      return <SectionErrorFallback />;
    }
    return this.props.children;
  }
}

// Использование: слои защиты
export function App() {
  return (
    <GlobalErrorBoundary>
      <Header />
      <SectionErrorBoundary>
        <MainContent />
      </SectionErrorBoundary>
      <SectionErrorBoundary>
        <Sidebar />
      </SectionErrorBoundary>
      <Footer />
    </GlobalErrorBoundary>
  );
}

Обработка асинхронных ошибок

Для асинхронного кода нужна своя обработка:

function UserProfile() {
  const [user, setUser] = useState(null);
  const [error, setError] = useState(null);

  useEffect(() => {
    // Асинхронная ошибка НЕ будет поймана Error Boundary
    fetchUser()
      .then((data) => setUser(data))
      .catch((err) => setError(err)); // Явно обрабатываем
  }, []);

  if (error) {
    return <ErrorMessage error={error} />;
  }

  if (!user) {
    return <LoadingSpinner />;
  }

  return <div>{user.name}</div>;
}

Современный подход: с использованием хуков (React 18+)

В React 18 можно использовать обычные функциональные компоненты с хуком для ловли ошибок:

import { useState, useEffect } from 'react';

function useErrorHandler(onError) {
  useEffect(() => {
    const handler = (event) => {
      if (event instanceof ErrorEvent) {
        onError(event.error);
      }
    };

    window.addEventListener('error', handler);
    window.addEventListener('unhandledrejection', (event) => {
      onError(event.reason);
    });

    return () => {
      window.removeEventListener('error', handler);
      window.removeEventListener('unhandledrejection', handler);
    };
  }, [onError]);
}

function App() {
  const [error, setError] = useState(null);
  useErrorHandler(setError);

  if (error) {
    return <ErrorPage error={error} />;
  }

  return <MainApp />;
}

Интеграция с сервисами мониторинга

class ErrorBoundary extends React.Component {
  componentDidCatch(error, errorInfo) {
    // Отправляем в Sentry
    Sentry.captureException(error, { contexts: { react: errorInfo } });

    // Отправляем в аналитику
    analytics.trackError({
      message: error.message,
      stack: error.stack,
      component: errorInfo.componentStack
    });

    // Логируем в консоль при разработке
    if (process.env.NODE_ENV === 'development') {
      console.error('Full error:', error);
      console.error('Component stack:', errorInfo.componentStack);
    }
  }

  render() {
    if (this.state.hasError) {
      return (
        <div className="error-page">
          <h1>Произошла ошибка</h1>
          <p>Наша команда уже уведомлена о проблеме</p>
          <button onClick={() => window.location.href = '/'}>
            На главную
          </button>
        </div>
      );
    }

    return this.props.children;
  }
}

Стратегия Error Boundaries

Полностью обернуть приложение:

  • Простейший подход
  • Одна ошибка = всё падает

Несколько уровней (рекомендуется):

<GlobalErrorBoundary>
  <Header />
  <SectionErrorBoundary section="news">
    <NewsSection />
  </SectionErrorBoundary>
  <SectionErrorBoundary section="profile">
    <ProfileSection />
  </SectionErrorBoundary>
</GlobalErrorBoundary>

При ошибке в ProfileSection упадёт только этот раздел, остальное приложение продолжит работать.

Когда использовать Error Boundary

  • Синхронные ошибки в render и lifecycle
  • Ошибки в дочерних компонентах
  • Критичные ошибки, после которых UI не может быть отрендерен

Не используй для:

  • Обработки асинхронных ошибок (используй try-catch)
  • Бизнес-логики (выбор тарифа, валидация)
  • Сетевых запросов (используй обработку в компоненте)

Ключевые выводы

  • Error Boundary — это компонент класса для обработки ошибок в дереве
  • Используй getDerivedStateFromError() и componentDidCatch()
  • Организуй несколько уровней для лучшей UX
  • Интегрируй с мониторингом (Sentry, DataDog)
  • Помни про асинхронные ошибки — они требуют своей обработки
  • Всегда имей fallback UI вместо белого экрана смерти

Это критичный паттерн для production приложений, обеспечивающий стабильность и пользовательский опыт.