Делал ли обертку для отлова ошибок в React
Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
Делал ли обертку для отлова ошибок в 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 приложений, обеспечивающий стабильность и пользовательский опыт.