Как обрабатывать ошибки в приложении 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:

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-индикаторов, глобального логирования, перехвата сбоев и интеграции с системами мониторинга. Это важно как для отладки, так и для стабильной работы в продакшне.