Зневадження React Native у 2026: DevTools, Reactotron, Radon IDE та Hermes Profiler

Практичний посібник із зневадження React Native додатків у 2026 році. Розбираємо DevTools, Reactotron, Radon IDE, профілювання з Hermes, Error Boundaries та інтеграцію Sentry — з реальними прикладами коду.

Вступ: чому зневадження — це наріжний камінь розробки React Native

React Native і досі залишається однією з топових платформ для кросплатформної мобільної розробки у 2026 році. Але давайте будемо чесними — зневадження (debugging) мобільних додатків залишається одним із найболючіших етапів усього процесу. Мости між JavaScript та нативним кодом, асинхронщина, управління станом і специфіка кожної платформи створюють такі виклики, яких у звичайній веб-розробці просто не існує.

Ще кілька років тому основним інструментом зневадження був Flipper — десктопний додаток від Meta. Він справлявся зі своєю роботою, але, якщо чесно, мав чимало проблем. У 2024 році команда React Native офіційно оголосила про припинення підтримки Flipper і представила React Native DevTools — нову платформу зневадження на базі Chrome DevTools Protocol. І це реально змінило гру.

Сьогодні у розробників є цілий арсенал потужних інструментів: вбудовані React Native DevTools, Reactotron, Radon IDE та інтегровані системи моніторингу помилок. У цьому посібнику ми детально розберемо кожен із них — коли і як використовувати, з практичними прикладами коду.

Незалежно від того, чи ви відстежуєте витік пам'яті, аналізуєте повільний рендеринг, чи досліджуєте мережеві запити — правильний інструмент може скоротити час пошуку помилки з годин до хвилин. Отже, давайте розбиратися.

React Native DevTools — новий стандарт зневадження

React Native DevTools — це офіційний інструмент, який замінив Flipper та старий підхід із зневадженням через Chrome. Побудований на основі Chrome DevTools, він дає глибоку інтеграцію з рушієм Hermes і дозволяє зневаджувати код безпосередньо на пристрої — без проксіювання через браузер.

Запуск React Native DevTools

Є два основних способи відкрити DevTools:

  • Через Dev Menu: Натисніть Cmd+D (iOS) або Cmd+M / Ctrl+M (Android) у емуляторі, потім оберіть "Open DevTools".
  • Через CLI: Натисніть клавішу j у терміналі, де запущено Metro bundler. Чесно кажучи, це найшвидший спосіб — я сам ним завжди користуюсь.

Після запуску відкриється вікно браузера з повноцінним інтерфейсом зневадження, де є декілька ключових панелей.

Console — інтерактивна консоль JavaScript

Панель Console — це не просто перегляд логів. Це повноцінний інтерактивний термінал, з'єднаний напряму з JavaScript-середовищем вашого додатка. Можна виконувати будь-які JS-вирази, звертатися до глобальних змінних, викликати функції і навіть маніпулювати станом додатка в реальному часі.

Ось приклад ефективного структурованого логування замість звичайного console.log:

// Замість простого console.log використовуйте структуроване логування

// Групування пов'язаних логів
console.group('🔄 Завантаження профілю користувача');
console.log('ID користувача:', userId);
console.time('fetchProfile');

try {
  const profile = await fetchUserProfile(userId);
  console.timeEnd('fetchProfile');
  console.log('Профіль отримано:', profile);
  console.table({
    "Ім'я": profile.name,
    'Email': profile.email,
    'Роль': profile.role,
    'Остання активність': profile.lastActive,
  });
} catch (error) {
  console.timeEnd('fetchProfile');
  console.error('Помилка завантаження профілю:', error);
  console.trace('Стек виклику при помилці');
} finally {
  console.groupEnd();
}

// Умовне логування — виводить повідомлення лише якщо умова false
console.assert(items.length > 0, 'Масив товарів порожній!', { items });

// Підрахунок кількості викликів
function handlePress(buttonId) {
  console.count(`Натискання кнопки ${buttonId}`);
  // ... логіка обробки
}

// Форматоване виведення об'єктів із вкладеністю
console.dir(complexNestedObject, { depth: 4, colors: true });

Особливо раджу звернути увагу на console.table() — вона чудово відображає масиви та об'єкти в табличному вигляді. А console.time() / console.timeEnd() незамінні для швидкого вимірювання часу виконання операцій.

Sources — перегляд коду та встановлення точок зупинки

Панель Sources дає повний доступ до вихідного коду вашого додатка. Завдяки source maps ви бачите оригінальний код, а не скомпільований бандл. Що тут можна робити:

  • Точки зупинки (Breakpoints): Клацніть на номері рядка — і все, точку зупинки встановлено. Коли виконання дійде до цього рядка, додаток призупиниться.
  • Умовні точки зупинки: Клацніть правою кнопкою на номері рядка → "Add conditional breakpoint". Наприклад, userId === 'admin' — зупинка спрацює лише для конкретного користувача.
  • Покрокове виконання: Step Over (F10), Step Into (F11) і Step Out (Shift+F11) для покрокового проходження коду.
  • Watch expressions: Додавайте вирази для спостереження за значеннями змінних під час зневадження.
  • Call Stack: Повний стек викликів, щоб зрозуміти, як виконання дійшло до поточної точки.

Для асинхронного коду надзвичайно корисна опція "Pause on exceptions" — вона автоматично зупиняє виконання при будь-якому необробленому виключенні. Рекомендую тримати її увімкненою.

Network — інспекція мережевих запитів (Expo)

Панель Network наразі повноцінно працює лише в Expo-проєктах (так, це обмеження). Але якщо ви на Expo — вона дає детальну інформацію про кожен HTTP-запит:

  • Список запитів із методом, URL, статусом відповіді та часом виконання.
  • Заголовки запиту та відповіді — перевірка авторизаційних токенів, content-type, кешування.
  • Тіло запиту та відповіді — з підсвіткою JSON.
  • Часові діаграми (Timing) — розбивка на DNS lookup, TCP connection, TLS handshake, TTFB та завантаження контенту.

Для проєктів без Expo мережеву інспекцію можна виконувати через Reactotron або Radon IDE — про них розкажемо далі.

Memory — профілювання пам'яті

Витоки пам'яті — це та проблема, яка може непомітно накопичуватись і потім раптово "вибухнути" крашем. Панель Memory допомагає їх знайти. Є два основних режими:

  • Heap Snapshot: Знімок усіх об'єктів у пам'яті на певний момент. Порівнюючи два знімки (скажімо, до та після переходу між екранами), можна виявити об'єкти, що не звільнилися.
  • Allocation Sampling: Записує профіль виділення пам'яті за певний період, показуючи, які функції споживають найбільше пам'яті.

Типовий сценарій: відкрийте екран зі списком, зробіть heap snapshot, перейдіть на інший екран і поверніться, зробіть другий snapshot — і порівняйте. Якщо об'єкти "не зникли" — у вас витік.

React DevTools Profiler — аналіз продуктивності рендерингу

React DevTools Profiler вбудовано прямо в React Native DevTools. Він записує сеанси рендерингу і показує:

  • Час рендерингу кожного компонента — у мілісекундах, з кольоровою індикацією (зелений — ок, жовтий — так собі, червоний — проблема).
  • Причини перерендерингу — змінилися props, state, чи батьківський компонент спровокував рендеринг.
  • Flame chart — візуалізація ієрархії компонентів із часом рендерингу.
  • Ranked chart — сортований список компонентів за часом рендерингу.

Обов'язково увімкніть опцію "Record why each component rendered" у налаштуваннях Profiler. Це справді неоціненно при оптимізації складних списків та форм — ви одразу бачите, що саме спричиняє зайві рендери.

Reactotron — потужний інспектор стану

Reactotron — це десктопний додаток від Infinite Red для інспекції React та React Native додатків. На відміну від DevTools, він спеціалізується саме на інспекції стану додатка, мережевих запитів і сховищ даних. Якщо у вас проєкт із Redux, MobX або Zustand — Reactotron стане вашим найкращим другом.

Встановлення та налаштування

Встановлення стало набагато простішим завдяки CLI:

# Встановлення залежностей
npm install --save-dev reactotron-react-native reactotron-redux

# Або для Expo-проєктів
npx expo install reactotron-react-native

Далі створіть файл конфігурації ReactotronConfig.js у кореневій теці проєкту:

// ReactotronConfig.js
import Reactotron from 'reactotron-react-native';
import { reactotronRedux } from 'reactotron-redux';
import AsyncStorage from '@react-native-async-storage/async-storage';
import mmkvPlugin from 'reactotron-react-native-mmkv';
import { storage } from './src/storage'; // ваш MMKV інстанс

const reactotron = Reactotron
  .setAsyncStorageHandler(AsyncStorage)
  .configure({
    name: 'MyApp',           // назва вашого додатка
    host: 'localhost',        // для емулятора
    // host: '192.168.1.100', // IP для реального пристрою
  })
  .useReactNative({
    asyncStorage: { ignore: ['secret'] }, // ігнорувати певні ключі
    networking: {
      ignoreUrls: /symbolicate|logs/,     // ігнорувати системні запити
    },
    editor: true,
    errors: { veto: (stackFrame) => false },
    overlay: true,
  })
  .use(reactotronRedux())        // плагін для Redux
  .use(mmkvPlugin({ storage }))  // плагін для MMKV
  .connect();

// Зручний доступ через console.tron у режимі розробки
if (__DEV__) {
  console.tron = reactotron;
}

export default reactotron;

Потім імпортуйте конфігурацію на самому початку вхідного файлу (це важливо — імпорт має бути першим!):

// index.js або App.js — імпорт має бути першим!
if (__DEV__) {
  require('./ReactotronConfig');
}

import { AppRegistry } from 'react-native';
import App from './src/App';
import { name as appName } from './app.json';

AppRegistry.registerComponent(appName, () => App);

Інтеграція з Redux

Щоб Reactotron міг інспектувати Redux-стор, потрібно додати enhancer при створенні стору:

// store.js
import { configureStore } from '@reduxjs/toolkit';
import Reactotron from '../ReactotronConfig';
import rootReducer from './reducers';

const store = configureStore({
  reducer: rootReducer,
  enhancers: (getDefaultEnhancers) => {
    const enhancers = getDefaultEnhancers();
    // Додаємо Reactotron enhancer тільки в режимі розробки
    if (__DEV__ && Reactotron.createEnhancer) {
      enhancers.push(Reactotron.createEnhancer());
    }
    return enhancers;
  },
});

export default store;

Після цього в Reactotron ви побачите кожну диспетчеризовану дію, зміни стану, і зможете використовувати "State Snapshots" для збереження та відновлення стану додатка. Це неймовірно зручно для відтворення складних багів.

Інспекція MMKV-сховища

MMKV фактично став стандартом для локального сховища в React Native завдяки своїй швидкодії. Плагін reactotron-react-native-mmkv дозволяє переглядати всі збережені ключі та значення в реальному часі і навіть змінювати їх прямо з Reactotron.

Моніторинг мережевих запитів

Reactotron автоматично перехоплює всі HTTP-запити через fetch або XMLHttpRequest — URL, метод, статус, час виконання, заголовки, тіло. Системні запити (наприклад, до Metro bundler) можна відфільтрувати через параметр ignoreUrls у конфігурації.

Кастомні команди та бенчмарки

Одна з моїх улюблених фіч — кастомні команди, які можна запускати прямо з десктопного інтерфейсу Reactotron:

// Реєстрація кастомної команди для скидання кешу
Reactotron.onCustomCommand({
  title: 'Очистити кеш',
  description: 'Видаляє всі кешовані дані додатка',
  command: 'clearCache',
  handler: () => {
    storage.clearAll();          // MMKV
    AsyncStorage.clear();        // AsyncStorage
    queryClient.clear();         // React Query
    console.tron.log('Кеш успішно очищено');
  },
});

// Бенчмарк для вимірювання часу операції
const benchmark = Reactotron.benchmark('Обробка великого масиву даних');
const processedData = heavyDataProcessing(rawData);
benchmark.stop(); // Виведе час виконання в Reactotron

Radon IDE — повноцінна IDE для React Native у VS Code

Radon IDE від Software Mansion — це розширення для VS Code та Cursor, яке перетворює ваш редактор на повноцінне середовище розробки React Native із вбудованим симулятором, зневаджувачем та інструментами інспекції. Так, це комерційний продукт, але він серйозно прискорює цикл розробки.

Встановлення та налаштування

Встановлення максимально просте — прямо з маркетплейсу VS Code:

  1. Відкрийте VS Code або Cursor.
  2. Перейдіть до Extensions (Ctrl+Shift+X / Cmd+Shift+X).
  3. Знайдіть "Radon IDE" та натисніть Install.
  4. Відкрийте проєкт React Native — Radon IDE автоматично його розпізнає.
  5. На бічній панелі з'явиться іконка Radon IDE — натисніть, щоб відкрити панель симулятора.

Radon IDE сам визначає конфігурацію проєкту (Expo, bare React Native, версію) і налаштовує середовище відповідно. Ніяких додаткових кроків.

Вбудована панель симулятора/емулятора

Мабуть, найкрутіша фіча Radon IDE — вбудований симулятор iOS або емулятор Android прямо у VS Code. Не треба перемикатися між вікнами — код і додаток видно одночасно. Панель підтримує:

  • Вибір пристрою та версії ОС.
  • Зміну орієнтації екрану.
  • Симуляцію жестів (tap, swipe, pinch).
  • Попередній перегляд компонентів у реальному часі при зміні коду.

Зневадження з точками зупинки

Radon IDE інтегрується зі вбудованим зневаджувачем VS Code. Встановлюєте точки зупинки прямо в редакторі — клацнули на лівому полі рядка, і готово. Коли виконання дійде до цього рядка, додаток призупиниться, ви побачите змінні в панелі Variables, Call Stack, зможете крокувати по коду. І все це без жодного launch.json чи інших файлів налаштувань. Просто працює.

Мережева панель

Radon IDE має власну мережеву панель, яка працює і в Expo, і в bare React Native проєктах. Вона перехоплює всі HTTP/HTTPS запити та WebSocket з'єднання. Це вирішує одну з головних проблем DevTools, де мережева панель обмежена лише Expo.

Підсвітка перерендерів компонентів

Ця фіча реально економить час. Radon IDE візуально підсвічує компоненти, які перерендерюються — навколо них з'являється кольорова рамка прямо в панелі симулятора. Чим яскравіший колір — тим частіше компонент оновлюється. Швидко знаходиш зайві рендери без необхідності відкривати React DevTools Profiler.

Запис та відтворення взаємодій

Функція Record and Replay записує послідовність дій користувача (натискання, свайпи, введення тексту) і відтворює їх автоматично. Корисно для:

  • Відтворення складних сценаріїв, що призводять до помилки.
  • Тестування після внесення змін у код.
  • Демонстрації багів колегам по команді.

Профілювання продуктивності з Hermes

Hermes — JavaScript-рушій, оптимізований саме для React Native (і рушій за замовчуванням з версії 0.70). Він дає потужні можливості профілювання, які допомагають знайти вузькі місця на рівні виконання JS-коду.

Активація Hermes Sampling Profiler

Hermes sampling profiler збирає дані про виконання функцій через регулярні інтервали — це дозволяє побудувати картину розподілу часу з мінімальним впливом на продуктивність самого додатка.

Щоб зібрати профіль:

  1. Відкрийте Dev Menu в додатку.
  2. Натисніть "Enable Sampling Profiler".
  3. Виконайте дії, які хочете профілювати (прокрутка списку, перехід між екранами тощо).
  4. Знову відкрийте Dev Menu → "Disable Sampling Profiler".
  5. Профіль збережеться як файл .cpuprofile на пристрої.

Збір та конвертація профілів

Після збору профілю його треба перенести на комп'ютер і конвертувати у формат Chrome DevTools:

# Копіювання профілю з Android-пристрою
adb pull /data/user/0/com.yourapp/cache/sampling-profiler-trace.cpuprofile .

# Встановлення трансформера профілів
npm install -g hermes-profile-transformer

# Конвертація у формат Chrome DevTools
hermes-profile-transformer sampling-profiler-trace.cpuprofile \
  --bundle-path ./android/app/build/generated/assets/createBundleReleaseJsAndAssets/index.android.bundle \
  --source-map-path ./android/app/build/generated/sourcemaps/react/release/index.android.bundle.map \
  --output-file chrome-profile.json

Потім відкрийте chrome-profile.json у Chrome DevTools (вкладка Performance → Load profile) для візуалізації.

Візуалізація Flame Charts

Flame chart (полум'яна діаграма) — мабуть, найінформативніший спосіб візуалізації профілю. Кожен горизонтальний блок — це виклик функції, його ширина показує час виконання. Вертикальна вкладеність відображає стек викликів.

На що звертати увагу:

  • Широкі блоки на верхніх рівнях — функції, що "їдять" найбільше часу.
  • Глибокі стеки — можлива надмірна вкладеність компонентів або рекурсія.
  • Повторювані патерни — компоненти, що рендеряться занадто часто.

Інтерпретація Chart View та Heavy View

Chart View показує хронологічний вигляд виконання на часовій шкалі — зліва направо. Корисно для розуміння послідовності подій та виявлення довгих синхронних операцій, що блокують потік.

Heavy (Bottom Up) View агрегує дані за функціями, показуючи загальний час у кожній функції незалежно від кількості викликів. Ідеально для пошуку "гарячих точок" — тих функцій, що сумарно споживають найбільше процесорного часу.

Програмне профілювання з react-native-release-profiler

Бібліотека react-native-release-profiler від Margelo — це справжня знахідка. Вона дозволяє збирати профілі навіть у release-збірках, що дуже корисно для профілювання реальних сценаріїв:

// Встановлення:
// npm install react-native-release-profiler

import {
  startProfiling,
  stopProfiling,
} from 'react-native-release-profiler';

// Компонент для профілювання критичного шляху
function ProductListScreen() {
  const [products, setProducts] = useState([]);

  const loadProducts = async () => {
    // Починаємо профілювання
    startProfiling();

    try {
      const response = await fetch('https://api.example.com/products');
      const data = await response.json();

      // Важка операція обробки даних
      const processed = data.map(item => ({
        ...item,
        formattedPrice: formatCurrency(item.price),
        thumbnail: generateThumbnailUrl(item.image),
        searchIndex: buildSearchIndex(item),
      }));

      setProducts(processed);
    } finally {
      // Зупиняємо профілювання та отримуємо результат
      const profilePath = await stopProfiling();
      console.log('Профіль збережено:', profilePath);

      // Тепер профіль можна завантажити на сервер
      // для подальшого аналізу
      await uploadProfile(profilePath);
    }
  };

  return (
    <FlatList
      data={products}
      renderItem={({ item }) => <ProductCard product={item} />}
      onEndReached={loadProducts}
    />
  );
}

// Утиліта для профілювання будь-якої асинхронної операції
async function profileAsync(label, operation) {
  console.time(label);
  startProfiling();

  try {
    const result = await operation();
    return result;
  } finally {
    const profilePath = await stopProfiling();
    console.timeEnd(label);
    console.log(`[Profiler] ${label}: ${profilePath}`);
  }
}

// Використання утиліти
await profileAsync('Ініціалізація додатка', async () => {
  await initDatabase();
  await loadUserPreferences();
  await prefetchCriticalData();
});

Error Boundaries та LogBox

Коли помилка все-таки трапляється (а вона трапиться, повірте), важливо мати механізм перехоплення і зрозумілого інформування користувача. React надає для цього Error Boundaries — спеціальні компоненти, що "ловлять" помилки рендерингу в дочірніх компонентах.

Реалізація кастомного Error Boundary

Error Boundary — це класовий компонент (так, у 2026 році все ще класовий — для цього є причина), який використовує методи getDerivedStateFromError та componentDidCatch:

import React, { Component } from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';

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

  // Викликається під час рендерингу, коли дочірній компонент кидає помилку
  static getDerivedStateFromError(error) {
    return { hasError: true, error };
  }

  // Викликається після рендерингу з помилкою
  // Тут можна логувати або надсилати на сервер
  componentDidCatch(error, errorInfo) {
    this.setState({ errorInfo });
    this.reportError(error, errorInfo);
  }

  reportError = (error, errorInfo) => {
    console.error('ErrorBoundary перехопив помилку:', {
      message: error.message,
      stack: error.stack,
      componentStack: errorInfo?.componentStack,
    });

    fetch('https://errors.example.com/report', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        error: error.toString(),
        componentStack: errorInfo?.componentStack,
        timestamp: new Date().toISOString(),
        appVersion: '1.0.0',
      }),
    }).catch(() => {
      // Ігноруємо помилку мережі при відправці звіту
    });
  };

  handleReset = () => {
    this.setState({
      hasError: false,
      error: null,
      errorInfo: null,
    });
    this.props.onReset?.();
  };

  render() {
    if (this.state.hasError) {
      if (this.props.fallback) {
        return this.props.fallback({
          error: this.state.error,
          resetError: this.handleReset,
        });
      }

      return (
        <View style={styles.container}>
          <Text style={styles.title}>Щось пішло не так</Text>
          <Text style={styles.message}>
            Виникла несподівана помилка. Спробуйте перезавантажити екран.
          </Text>
          {__DEV__ && (
            <Text style={styles.errorDetail}>
              {this.state.error?.toString()}
            </Text>
          )}
          <TouchableOpacity
            style={styles.button}
            onPress={this.handleReset}
          >
            <Text style={styles.buttonText}>Спробувати знову</Text>
          </TouchableOpacity>
        </View>
      );
    }

    return this.props.children;
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 24,
    backgroundColor: '#FEF2F2',
  },
  title: {
    fontSize: 22,
    fontWeight: '700',
    color: '#991B1B',
    marginBottom: 12,
  },
  message: {
    fontSize: 16,
    color: '#7F1D1D',
    textAlign: 'center',
    marginBottom: 16,
    lineHeight: 24,
  },
  errorDetail: {
    fontSize: 12,
    color: '#B91C1C',
    fontFamily: 'monospace',
    backgroundColor: '#FEE2E2',
    padding: 12,
    borderRadius: 8,
    marginBottom: 16,
    width: '100%',
  },
  button: {
    backgroundColor: '#DC2626',
    paddingHorizontal: 24,
    paddingVertical: 12,
    borderRadius: 8,
  },
  buttonText: {
    color: '#FFFFFF',
    fontSize: 16,
    fontWeight: '600',
  },
});

export default ErrorBoundary;

А ось як використовувати Error Boundary в додатку:

// App.js — огортаємо весь додаток або окремі екрани
import ErrorBoundary from './components/ErrorBoundary';

function App() {
  return (
    <ErrorBoundary
      fallback={({ error, resetError }) => (
        <CustomErrorScreen error={error} onRetry={resetError} />
      )}
      onReset={() => {
        // Очищення стану при скиданні помилки
        queryClient.clear();
      }}
    >
      <NavigationContainer>
        <RootNavigator />
      </NavigationContainer>
    </ErrorBoundary>
  );
}

Бібліотека react-error-boundary

Якщо хочете зручніший API (особливо з функціональними компонентами), подивіться на бібліотеку react-error-boundary:

import { ErrorBoundary, useErrorBoundary } from 'react-error-boundary';

// Функціональний компонент може програмно викидати помилку
function DataLoader({ userId }) {
  const { showBoundary } = useErrorBoundary();

  const loadData = async () => {
    try {
      const data = await fetchUserData(userId);
      setUser(data);
    } catch (error) {
      // Передаємо помилку до найближчого Error Boundary
      showBoundary(error);
    }
  };

  // ...
}

// Використання з декларативним API
function ProfileScreen() {
  return (
    <ErrorBoundary
      FallbackComponent={ErrorFallback}
      onError={(error, info) => {
        logErrorToService(error, info.componentStack);
      }}
      onReset={(details) => {
        if (details.reason === 'imperative-api') {
          // Скидання через showBoundary
        } else {
          // Скидання через кнопку retry
          navigation.replace('Profile');
        }
      }}
      resetKeys={[userId]} // Автоскидання при зміні userId
    >
      <DataLoader userId={userId} />
    </ErrorBoundary>
  );
}

Налаштування LogBox

LogBox — система відображення попереджень та помилок у React Native під час розробки. Жовті банери — warnings, червоні — errors. Іноді деякі з них не критичні і просто заважають:

import { LogBox } from 'react-native';

// Ігнорувати конкретні попередження за текстом
LogBox.ignoreLogs([
  'ViewPropTypes will be removed',
  'AsyncStorage has been extracted from react-native',
  /Require cycle:.*node_modules/,
]);

// Повністю вимкнути LogBox (НЕ рекомендується!)
// LogBox.ignoreAllLogs(true);

Важливо: ніколи не використовуйте LogBox.ignoreAllLogs() на постійній основі. Це приховує потенційно важливі попередження. Ігноруйте лише конкретні, відомі попередження, що не впливають на роботу вашого додатка.

Інтеграція Sentry для моніторингу в продакшені

Зневадження під час розробки — це тільки половина справи. Коли додаток потрапляє до реальних користувачів, потрібен надійний сервіс моніторингу. Sentry — це, мабуть, найпопулярніше рішення для React Native: стеки викликів із source maps, метадані пристрою, breadcrumbs (ланцюжок подій перед помилкою). Все, що потрібно для швидкого розслідування.

Встановлення та налаштування @sentry/react-native

# Встановлення SDK
npx expo install @sentry/react-native
# або для bare React Native
npm install @sentry/react-native

# Запуск майстра налаштування (налаштує нативні модулі)
npx @sentry/wizard@latest -i reactNative

Ініціалізацію Sentry потрібно виконати якомога раніше — до рендерингу будь-яких компонентів:

// App.js
import * as Sentry from '@sentry/react-native';

Sentry.init({
  dsn: 'https://[email protected]/0',
  tracesSampleRate: 1.0,  // 100% транзакцій у dev, зменшіть у prod
  profilesSampleRate: 0.3, // Профілювання 30% транзакцій
  environment: __DEV__ ? 'development' : 'production',
  beforeSend(event) {
    if (event.exception) {
      event.contexts = {
        ...event.contexts,
        appState: {
          isAuthenticated: store.getState().auth.isLoggedIn,
          currentScreen: navigationRef.getCurrentRoute()?.name,
        },
      };
    }
    return event;
  },
});

// Огортання кореневого компонента
export default Sentry.wrap(App);

Інтеграція Error Boundary із Sentry

Sentry має власний Error Boundary, який автоматично відправляє помилки рендерингу на сервер:

import * as Sentry from '@sentry/react-native';

function App() {
  return (
    <Sentry.ErrorBoundary
      fallback={({ error, resetError }) => (
        <ErrorFallbackScreen error={error} onRetry={resetError} />
      )}
      beforeCapture={(scope) => {
        scope.setTag('boundary', 'root');
        scope.setLevel('fatal');
      }}
    >
      <NavigationContainer>
        <RootNavigator />
      </NavigationContainer>
    </Sentry.ErrorBoundary>
  );
}

Моніторинг продуктивності та відстеження транзакцій

Sentry Performance Monitoring дозволяє відстежувати час критичних операцій. Це дуже зручно для розуміння, де саме "гальмує" ваш додаток у продакшені:

import * as Sentry from '@sentry/react-native';

// Автоматичне відстеження навігації
const routingInstrumentation =
  Sentry.reactNavigationIntegration({
    enableTimeToInitialDisplay: true,
  });

// Ручне створення транзакцій для критичних операцій
async function processCheckout(cartItems) {
  return Sentry.startSpan(
    { name: 'checkout.process', op: 'task' },
    async (span) => {
      const order = await Sentry.startSpan(
        { name: 'checkout.createOrder', op: 'http.client' },
        () => createOrder(cartItems)
      );

      await Sentry.startSpan(
        { name: 'checkout.processPayment', op: 'http.client' },
        () => processPayment(order.id)
      );

      await Sentry.startSpan(
        { name: 'checkout.sendConfirmation', op: 'http.client' },
        () => sendConfirmationEmail(order)
      );

      return order;
    }
  );
}

У дашборді Sentry ви побачите розподіл часу між етапами — наприклад, оформлення замовлення — і зможете виявляти повільні операції та відстежувати тренди з часом.

Найкращі практики зневадження React Native

Тепер, коли ми розглянули всі інструменти, давайте поговоримо про те, коли який із них краще використовувати. Бо мати інструменти — це одне, а знати, коли дістати потрібний — зовсім інше.

Коли використовувати який інструмент

  • React Native DevTools — ваш основний щоденний інструмент. Покрокове зневадження, консоль, аналіз рендерингу, профілювання пам'яті. Починайте завжди з нього.
  • Reactotron — коли треба копатися в стані Redux/MobX/Zustand, дивитися AsyncStorage/MMKV, або потрібні кастомні команди для зневадження. Незамінний для додатків зі складним стейт-менеджментом.
  • Radon IDE — коли хочете максимально інтегрований досвід без перемикання між вікнами. Особливо зручний для прототипування.
  • Hermes Profiler — коли щось "гальмує" і треба зрозуміти, які саме функції винні.
  • Sentry — для продакшену. Налаштовуйте з першого дня проєкту, серйозно.

Організація логування: console.log проти структурованого підходу

Давайте будемо чесними — всі ми грішимо хаотичним console.log. Але краще витратити трохи часу на структурований підхід:

// logger.js — централізований модуль логування
const LogLevel = {
  DEBUG: 0,
  INFO: 1,
  WARN: 2,
  ERROR: 3,
};

const currentLevel = __DEV__ ? LogLevel.DEBUG : LogLevel.ERROR;

const logger = {
  debug: (tag, message, data) => {
    if (currentLevel <= LogLevel.DEBUG) {
      console.log(`[DEBUG][${tag}]`, message, data || '');
    }
  },

  info: (tag, message, data) => {
    if (currentLevel <= LogLevel.INFO) {
      console.info(`[INFO][${tag}]`, message, data || '');
    }
  },

  warn: (tag, message, data) => {
    if (currentLevel <= LogLevel.WARN) {
      console.warn(`[WARN][${tag}]`, message, data || '');
    }
  },

  error: (tag, message, error) => {
    if (currentLevel <= LogLevel.ERROR) {
      console.error(`[ERROR][${tag}]`, message, error);
      Sentry.captureException(error, {
        tags: { component: tag },
        extra: { message },
      });
    }
  },
};

export default logger;

// Використання
import logger from './logger';

function UserProfile({ userId }) {
  logger.debug('UserProfile', 'Рендеринг профілю', { userId });

  const loadProfile = async () => {
    logger.info('UserProfile', 'Завантаження профілю', { userId });
    try {
      const profile = await api.getProfile(userId);
      logger.debug('UserProfile', 'Профіль завантажено', profile);
    } catch (error) {
      logger.error('UserProfile', 'Помилка завантаження профілю', error);
    }
  };

  // ...
}

Чому це краще:

  • Логи мають єдиний формат — легко фільтрувати за тегом або рівнем.
  • У release-збірках debug- та info-логи автоматично вимикаються.
  • Помилки самі летять у Sentry.
  • Не треба шукати і видаляти console.log перед релізом.

Робочий процес профілювання продуктивності

Ефективне профілювання — це не хаотичне "а давайте подивимося". Є чіткий алгоритм:

  1. Визначте проблему: Що саме повільно — завантаження екрану, прокрутка, анімація, перехід?
  2. Виміряйте базу: console.time() або react-native-release-profiler для числових показників до оптимізації.
  3. Профілюйте з Hermes: Зберіть профіль і подивіться flame chart.
  4. Аналізуйте рендеринг: React DevTools Profiler покаже зайві перерендери.
  5. Оптимізуйте: React.memo(), useMemo(), useCallback() — все це ваші друзі.
  6. Перевіряйте: Повторіть вимірювання. Якщо цифри не покращилися — шукайте далі.

Тестування на реальних пристроях проти емуляторів

Емулятори — зручно для повсякденної розробки, але є важливі нюанси:

  • Продуктивність: Емулятори працюють на потужностях вашого Mac, тому додаток летить. А на бюджетному Android за $150 — вже не так. Завжди тестуйте продуктивність на реальних пристроях.
  • Пам'ять: Витік пам'яті, непомітний на Mac з 16 ГБ RAM, може крашнути додаток на пристрої з 2 ГБ.
  • Мережа: Реальний повільний 3G або нестабільний WiFi емулятор не покаже. Використовуйте Network Link Conditioner (iOS) або налаштування мережі емулятора Android.
  • Нативні функції: Камера, GPS, Bluetooth, Push-сповіщення — для цього потрібен реальний пристрій.

Мій підхід такий: емулятори для щоденної розробки, але фінальне тестування та профілювання — обов'язково на кількох реальних пристроях різного класу.

Додаткові поради

  • Увімкніть Strict Mode: <React.StrictMode> виконує подвійний рендеринг у dev-режимі, що допомагає виявити побічні ефекти. Трохи дратує, але працює.
  • Використовуйте TypeScript: Строга типізація реально зменшує кількість runtime-помилок. Більшість багів ловиться ще до запуску.
  • ESLint з плагіном react-hooks: Правило exhaustive-deps врятує від поширених помилок з useEffect і useCallback.
  • Автоматизуйте: TypeScript, ESLint, тести в CI/CD — нехай машина ловить помилки до потрапляння в production.

Висновок

Екосистема зневадження React Native у 2026 році реально дозріла. Перехід від Flipper до React Native DevTools став важливим кроком, і загалом інструменти стали набагато зручнішими та інтегрованішими.

Підсумуємо:

  • React Native DevTools — основний інструмент для повсякденної розробки: покрокове зневадження, аналіз рендерингу, профілювання пам'яті.
  • Reactotron — незамінний для складного стейт-менеджменту, мережевого моніторингу та інспекції сховищ.
  • Radon IDE — для тих, хто цінує інтегрований досвід і мінімум перемикання контексту.
  • Hermes Profiler та react-native-release-profiler — коли треба розібратися з продуктивністю на глибокому рівні.
  • Error Boundaries та Sentry — захист від несподіваних помилок і моніторинг у реальних умовах.

Що далі? З розвитком нової архітектури React Native (Fabric, TurboModules) інструменти зневадження теж еволюціонують. Очікується підтримка мережевої інспекції в DevTools для bare-проєктів, покращення Reactotron для нової архітектури та навіть AI-асистоване зневадження в IDE.

Вкладіть час у вивчення цих інструментів і побудову ефективного робочого процесу — повірте, це окупиться багаторазово під час розробки та підтримки ваших React Native додатків.

Про Автора Editorial Team

Our team of expert writers and editors.