Error Boundaries
Error Boundary — React-компонент, который перехватывает JavaScript-ошибки в дочернем дереве и отображает fallback UI вместо краша всего приложения.
Зачем нужно
Без Error Boundaries любая необработанная ошибка в компоненте размонтирует всё дерево React и пользователь видит белый экран. Error Boundaries позволяют изолировать сбой: упавший виджет показывает сообщение об ошибке, остальная часть приложения продолжает работать. Это критически важно для производственных приложений — аналог try/catch для компонентного дерева.
Где используется
- Оборачивание виджетов дашбордов, каждый из которых может упасть независимо
- Защита маршрутов в react-router (каждый route за своим Error Boundary)
- Оборачивание сторонних компонентов с непредсказуемым поведением
- Разграничение критической и некритической части UI
Реализация Error Boundary
Error Boundary можно реализовать только через class-компонент (хуки не перехватывают ошибки рендеринга):
import React from 'react';
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false, error: null };
}
// Вызывается при ошибке в дочернем дереве
// Используется для обновления state и отображения fallback
static getDerivedStateFromError(error) {
return { hasError: true, error };
}
// Вызывается после getDerivedStateFromError
// Используется для логирования ошибки
componentDidCatch(error, info) {
console.error('Error Boundary поймал ошибку:', error);
console.error('Стек компонентов:', info.componentStack);
// Здесь можно отправить ошибку в Sentry, Datadog и т.д.
// logErrorToService(error, info);
}
render {
if (this.state.hasError) {
// Кастомный fallback или переданный через пропс
if (this.props.fallback) {
return this.props.fallback;
}
return (
<div role="alert" style={{ padding: '16px', color: 'red' }}>
<h2>Что-то пошло не так</h2>
<button onClick={ => this.setState({ hasError: false, error: null })}>
Попробовать снова
</button>
</div>
);
}
return this.props.children;
}
}
// Использование
function App() {
return (
<div>
<ErrorBoundary fallback={<p>Шапка недоступна</p>}>
<Header />
</ErrorBoundary>
<ErrorBoundary fallback={<p>Контент временно недоступен</p>}>
<MainContent />
</ErrorBoundary>
{/* Каждый виджет изолирован */}
<ErrorBoundary fallback={<p>Виджет недоступен</p>}>
<DataWidget />
</ErrorBoundary>
</div>
);
}
Обёртка-компонент с react-error-boundary
Библиотека react-error-boundary упрощает использование:
import { ErrorBoundary } from 'react-error-boundary';
function ErrorFallback({ error, resetErrorBoundary }) {
return (
<div role="alert">
<p>Ошибка: {error.message}</p>
<button onClick={resetErrorBoundary}>Обновить</button>
</div>
);
}
function App() {
return (
<ErrorBoundary
FallbackComponent={ErrorFallback}
onError={(error, info) => logError(error, info)}
onReset={ => { /* сбросить состояние приложения */ }}
>
<MyComponent />
</ErrorBoundary>
);
}
Частые ошибки
- Error Boundaries не перехватывают асинхронные ошибки — ошибки в
setTimeout, fetch-запросах или обработчиках событий нужно обрабатывать вручную через try/catch. - Один Error Boundary на всё приложение — при одной ошибке упадёт весь UI; оборачивайте отдельные секции.
- Не логируют ошибки в
componentDidCatch— ошибки должны отправляться в систему мониторинга (Sentry, Bugsnag). - Не предусматривают сброс — без кнопки «попробовать снова» пользователь вынужден перезагружать страницу.