Как обрабатывать ошибки в приложении React Native?
Обработка ошибок в React Native — это важный аспект разработки, позволяющий улучшить стабильность приложения, повысить UX, отлавливать баги и контролировать сбои. Ошибки могут возникать в JavaScript-коде, в API-запросах, в нативных модулях, а также при взаимодействии с файловой системой, Bluetooth, GPS и т.д. Важно учитывать разные уровни: синхронные, асинхронные и фатальные ошибки.
1. Обработка ошибок в JavaScript-коде
try/catch используется для синхронных и async/await операций.
try {
const response = await fetch('https://example.com/data');
const data = await response.json();
} catch (error) {
console.error('Ошибка запроса:', error.message);
}
Если используется then/catch:
fetch('https://example.com/data')
.then(response => response.json())
.catch(error => {
console.error('Ошибка:', error);
});
2. Обработка ошибок на уровне компонентов (Error Boundaries)
React предоставляет механизм Error Boundaries — компоненты, отлавливающие ошибки в фазе рендера, жизненного цикла и конструкторах дочерних компонентов.
Работают только с классовыми компонентами:
class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, info) {
// логгирование, отправка на сервер
console.log(error, info);
}
render() {
if (this.state.hasError) {
return <Text>Произошла ошибка</Text>;
}
return this.props.children;
}
}
Применение:
<ErrorBoundary>
<MyComponent />
</ErrorBoundary>
Error Boundaries не ловят:
-
ошибки в обработчиках событий (onPress, onChangeText)
-
асинхронные ошибки (в setTimeout, fetch)
-
ошибки в серверных данных
3. Обработка ошибок в обработчиках событий
Поскольку ErrorBoundary не ловит ошибки в функциях обратного вызова, их нужно оборачивать в try/catch:
const onPressButton = () => {
try {
throw new Error('Ошибка при нажатии');
} catch (e) {
Alert.alert('Ошибка', e.message);
}
};
4. Глобальный перехват ошибок
Для перехвата необработанных JS ошибок можно использовать:
import { LogBox } from 'react-native';
LogBox.ignoreAllLogs(); // временно отключить предупреждения
Глобальный перехват ошибок:
ErrorUtils.setGlobalHandler((error, isFatal) => {
if (isFatal) {
Alert.alert('Критическая ошибка', error.message);
} else {
console.warn(error);
}
});
На практике чаще используются сторонние решения, описанные ниже.
5. Работа с Promise без await
Если используется обычный Promise без await, ошибки могут «теряться», если не использовать .catch():
fetch('https://example.com')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));
6. Обработка ошибок в API-запросах
Для централизованной обработки ошибок можно создать функцию-обёртку:
async function fetchWithHandler(url) {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(\`Ошибка ${response.status}\`);
}
return await response.json();
} catch (e) {
throw new Error('Сетевая ошибка');
}
}
7. Использование axios с интерсепторами
axios позволяет перехватывать ошибки в одном месте:
import axios from 'axios';
axios.interceptors.response.use(
response => response,
error => {
console.log('Ошибка:', error.message);
return Promise.reject(error);
}
);
8. Отображение ошибок пользователю
Используйте:
-
Alert.alert() — стандартный способ для модальных уведомлений
-
Toast — через react-native-toast-message или react-native-root-toast
-
UI-компоненты: Text, Snackbar, Modal
Alert.alert('Ошибка', 'Что-то пошло не так');
9. Интеграция систем мониторинга ошибок
Чтобы собирать ошибки с продакшн-устройств, интегрируют:
- Sentry — https://sentry.io
- Bugsnag — https://www.bugsnag.com
- Firebase Crashlytics — https://firebase.google.com/products/crashlytics
Пример установки Sentry:
npx @sentry/wizard -i reactNative -p ios android
Sentry автоматически регистрирует JS и нативные ошибки, позволяет видеть стек вызовов, устройство, ОС, версию, и добавлять breadcrumbs.
10. Crash reporting в Expo
Для приложений на Expo можно использовать:
-
expo-sentry
-
expo-error-boundary
-
expo-dev-client + react-native-exception-handler
11. Сторонние утилиты и хуки
Можно создать собственный хук для отображения и логирования ошибок:
function useErrorHandler() {
return (error) => {
console.log(error);
Alert.alert('Ошибка', error.message || 'Неизвестная ошибка');
};
}
Применение:
const handleError = useErrorHandler();
try {
// ...
} catch (e) {
handleError(e);
}
12. Ошибки в нативных модулях
Если используешь NativeModules или TurboModules, ошибки оттуда надо ловить как обычные JS-ошибки:
try {
await NativeModules.MyModule.doSomething();
} catch (e) {
Alert.alert('Нативная ошибка', e.message);
}
13. Работа с UnhandledPromiseRejection
С версии React Native 0.63+ можно использовать:
process.on('unhandledRejection', (reason, promise) => {
console.error('Unhandled rejection', reason);
});
14. Индикация "ошибки в UI"
Многие приложения реализуют UX-паттерн:
-
Показывают ActivityIndicator при загрузке
-
Отображают сообщение об ошибке при сбое
-
Кнопку "Повторить"
{loading ? (
<ActivityIndicator />
) : error ? (
<Text>Произошла ошибка</Text>
) : (
<Content />
)}
Грамотная обработка ошибок в React Native — это сочетание локальных проверок (try/catch, Alert), UI-индикаторов, глобального логирования, перехвата сбоев и интеграции с системами мониторинга. Это важно как для отладки, так и для стабильной работы в продакшне.