РозробкаБудь-який рівень

React Native

React Native — це фреймворк, який виконує React-компоненти в рушії JavaScript на телефоні й перетворює їх на справжні в’ю iOS та Android, а не на вебсторінку. Через цей поділ вебкоманда може випустити застосунок, що відчувається нативним, — і через нього ж типовий збій тут — екран, який перестає відповідати, поки JavaScript зайнятий. Сторінка починається з шістнадцяти речей, які робить екран, і того, що рухається далі, коли потік JavaScript заблоковано; далі — нова архітектура, списки й зображення, Expo й оновлення «по повітрю», релізи до 0.87 і дедлайни магазинів на 2026 рік, що насправді спільне, п’ять задокументованих кейсів, зокрема повернення Shopify до нативу у вересні 2026 року, і те, де все це вироджується.

Поточна версія
0.87 · серп. 2026; 0.88 — 12 жовт.
Модель
Ваш JS в одному потоці, справжні нативні в’ю
Підтримка
Три останні мінорні версії; нова — приблизно що два місяці

Що рухається, коли JavaScript зайнятий, — шістнадцять речей, які робить екран

Екран на React Native — це дві програми, що розмовляють між собою. Ваш React-код виконується в одному потоці JavaScript. В’ю, яких торкається користувач, належать -потоку платформи, його ще називають головним. Здебільшого цієї різниці не видно. Вона стає видимою тієї миті, коли потік JavaScript зайнятий — розбирає велику відповідь, перерендерює довгий список, рахує щось важке, — бо все, що потребує JavaScript, чекає, а все, що не потребує, рухається далі. Тож корисне питання до будь-якої частини екрана — не «чи швидкий React Native?». Воно таке: «який потік це виконує і що побачить користувач, якщо цей потік буде зайнятий пів секунди?». Ось шістнадцять речей, які робить екран. Наступні розділи посилаються на рядки за номерами.

#Що робить екранДе виконуєтьсяЯкщо JS зайнятий 500 мсЗахід
1Скрол уже відрендереного спискуUI-потік — нативний scroll viewСкролиться плавно даліНічого: нативний скрол — типова поведінка
2Анімація, запущена з useNativeDriver: trueUI-потік, щойно запущенаНе зупиняєтьсяNative driver усюди, де він підтримується; з 0.85 він може анімувати й властивості розкладки (експериментально)
3Жест, який ведуть Gesture Handler і ворклет ReanimatedUI-потікЙде за пальцемGesture Handler із Reanimated для всього, що йде за пальцем
4Декодування й показ зображеньНативний конвеєр зображень, поза потоком JSЗображення вантажаться даліЗапитуйте зображення під розмір показу — декодований піксель займає 4 байти
5Перехід нативного стека, що вже почавсяUI-потік (react-native-screens)Завершується плавноНативний стек-навігатор, а не анімований із JS
6Набір тексту в TextInputПоле нативне; onChangeText — у JSСимволи з’являються; контрольоване value, яке JS ставить на кожне натискання, може сперечатися з нативним текстомПоля вільного тексту — неконтрольовані (defaultValue), а шлях натискання — дешевий
7Тап по PressableДотик ловить натив; onPress і стиль pressed — у JSДія — а на iOS і відгук натискання — приходить пізноКороткі обробники; нативний відгук (android_ripple, кнопки Gesture Handler)
8Заголовок, що йде за скролом через onScroll і setStateПотік JS, на кожну подію скролуВідстає від пальця, потім стрибаєAnimated.event з native driver або useAnimatedScrollHandler з Reanimated
9Анімація через setState або через Animated без native driverПотік JS, кожен кадрЗастигає, потім стрибає в кінецьРядки 2 і 3
10Нові рядки віртуалізованого списку під час скролуЇх рендерить потік JSПорожні клітинки там, де рядки ще не відрендереноFlashList або налаштований FlatList (getItemLayout, windowSize) з дешевими мемоїзованими рядками
11Таймер — setTimeout, setIntervalПотік JSСпрацьовує пізноНіколи не відмірюйте JS-таймером анімацію чи дедлайн
12Відповідь на fetchЗапит іде нативною мережею; колбек — у JSДані потрапляють на екран пізно — сам запит не був повільнішимМалі відповіді, пагінація, жодного розбору на шляху рендеру
13Перерендер після зміни стану — рендер React і розкладка YogaПотік JSЕкран показує попередній стан, доки обидва не завершатьсяОпустити стан нижче, мемоїзація, React Compiler — ті самі правила, що й у вебі
14Синхронний виклик нативного модуля через JSIПотік JS чекає на нативний кодБлокує JS на весь час нативного викликуСинхронно — лише робота на мікросекунди; диск і мережа — асинхронно
15Розбір 5 МБ JSON, сортування 10 000 елементів, важкий редʼюсерПотік JSЦе і є ті 500 мсПросіть у сервера менше; рахуйте заздалегідь; переносьте роботу в нативний код
16Старт — завантаження бандла й рендер першого екранаПотік JSСплеш-екран не зникаєБайткод Hermes (типово); менше роботи до першого екрана; екрани вантажаться, коли їх відкривають
Ілюстративний відрізок у 800 мс, коли розбір 5 МБ JSON тримає потік JavaScript пів секунди. Усе, що працює в UI-потоці, проходить наскрізь: скрол уже відрендереного списку, анімація, запущена з native driver, жест, який веде Reanimated. Усе, що потребує обміну з JavaScript, стає: анімація з JavaScript застигає, а потім стрибає, тап отримує свій onPress на 440 мс пізніше, а віртуалізований список показує порожні клітинки, бо нові рядки рендерить JavaScript. Виправлення — два кроки: те, що має бути плавним, — в UI-потік, а роботу JavaScript — меншою.

Два потоки й перехід: нова архітектура

<View> у React Native — це не div і не малюнок. Він стає справжнім UIView на iOS і справжнім android.view.View на Android, які створює й малює платформа. Тому скрол має правильну фізику, клавіатура поводиться коректно, а читачі екрана працюють без додаткових зусиль: нічого з цього не переписано, операційна система робить свою роботу. З тієї ж причини редизайн операційної системи доходить до застосунку на React Native компонент за компонентом, щойно застосунок перезібрано, — сторінка про Flutter показує цю різницю на прикладі iOS 26.

З React Native 0.82 нова архітектура — єдина. Ваш React-код виконується в потоці JavaScript, і в типовому випадку там само відбуваються рендер і розкладка: React будує shadow tree на C++, і Yoga там же його вимірює. UI-потік — головний потік платформи — лише застосовує отримані зміни до справжніх нативних в’ю і відповідає за нативний скрол і жести. Сторони спілкуються через JSI, що викликає навпростець замість пакетних JSON-повідомлень старого мосту. Усе, що потребує потоку JavaScript, чекає, поки той зайнятий, — тому жест, анімований в UI-потоці, лишається плавним, а анімований із JavaScript смикається.

Зміна потрапляє на екран у три кроки. Перший — рендер: React виконує ваші компоненти в потоці JavaScript і будує дерево елементів, а рендерер перетворює його на shadow tree — копію структури екрана, що живе в C++. Другий — розкладка: Yoga, рушій flexbox на C++, рахує розмір і позицію кожного вузла. У типовому випадку обидва кроки відбуваються в потоці JavaScript; термінове оновлення, як-от відповідь на дотик, натомість можуть відрендерити синхронно в UI-потоці. Третій — монтування: UI-потік порівнює нове дерево з тим, що на екрані, і застосовує лише різницю: створити цю в’ю, оновити ту, прибрати третю. UI-потік ніколи не виконує ваш React-код. Він лише застосовує результат.

Початковий задум з’єднував дві сторони «мостом»: кожне повідомлення серіалізували в , ставили в чергу й доставляли пакетами, асинхронно. Це працювало й породило фірмовий збій фреймворку: зайнятий потік JavaScript надсилав вказівки пізно, і кадри втрачалися. Нова архітектура замінює міст трьома частинами. JSI, JavaScript Interface, дозволяє JavaScript тримати пряме посилання на об’єкт C++ і викликати його синхронно, без жодного JSON посередині. Fabric — це описаний вище рендерер, збудований на JSI. TurboModules — нативні модулі, які завантажуються під час першого використання, а не всі на старті, і чиї типи Codegen генерує з типізованої специфікації, тож розбіжність між сигнатурою в JavaScript і нативною падає ще на збірці.

ВерсіяВихідЩо змінилося
0.68берез. 2022Нова архітектура доступна як опція
0.74квіт. 2024Режим без мосту типово ввімкнено в новій архітектурі
0.76жовт. 2024Нова архітектура типово ввімкнена; виходять React Native DevTools
0.79квіт. 2025JavaScriptCore переїжджає в пакет спільноти; віддалене налагодження в Chrome прибрано
0.80черв. 2025Стару архітектуру заморожено: без виправлень, без тестування, попередження в DevTools
0.82жовт. 2025Лише нова архітектура: newArchEnabled=false ігнорується
0.84лют. 2026Hermes V1 типово; старий код прибрано з iOS-збірок; попередньо скомпільовані бінарники iOS
0.85квіт. 2026Новий бекенд анімацій для Animated і Reanimated, зроблений разом із Software Mansion
0.87серп. 2026Строгий TypeScript API типово; глибокі імпорти прибрано; Swift Package Manager (експериментально)

Рушій JavaScript — Hermes, який Meta зробила саме для React Native. Він компілює JavaScript у байткод під час збірки застосунку, тож телефон не розбирає вихідний код на старті, — це перший захід із рядка 16. Hermes V1, перебудований компілятор і віртуальна машина, став типовим у 0.84; на застосунку Expensify команда React Native виміряла загальний час до інтерактивності на 7,6% коротший на Android і на 2,5% — на iOS. JavaScriptCore, рушій Safari, пішов з ядра в 0.79 і живе далі як пакет спільноти.

Списки, перерендери й зображення: звідки береться «React Native повільний»

Майже кожна скарга «React Native повільний» зводиться до рядків 10, 13 чи 15 — список, зайвий перерендер або забагато роботи в потоці JavaScript — або до рядка 4, зображення, якому ніхто не змінив розмір. Списки — першими, бо вони є майже на кожному екрані. Довгий список через .map() у ScrollView монтує кожен рядок, видимий чи ні. FlatList натомість віртуалізований: він монтує вікно рядків навколо екрана й демонтує решту. Типово він спершу рендерить 10 рядків, потім додає по 10 за пакет кожні 50 мс і тримає вікно заввишки 21 екран — десять угорі, десять унизу й видимий. Коли користувач гортає ривком швидше, ніж JavaScript встигає рендерити нові рядки, список показує порожнечу там, де мали бути рядки. Документація називає це порожніми ділянками (blank areas).

Список на 1000 елементів, виведений через .map() у ScrollView, монтує всі 1000 рядків, хоч би хто до них догортав. FlatList монтує вікно навколо екрана — типово на 21 екран, десять угорі й десять унизу — і рендерить нові рядки в JavaScript, коли вікно зсувається, тож швидкий ривок може його випередити й показати порожні клітинки. FlashList v2 тримає приблизно екран клітинок і віддає клітинку, що пішла вгорі, наступному елементу внизу, тож під час скролу майже нічого не створює. Смуги не в масштабі.
НалаштуванняТиповоЩо на що міняє
keyExtractorіндексСтабільний id на елемент тримає стан рядка разом із рядком, коли елементи вставляють
getItemLayout—Рядки відомої висоти не міряють; прокрутка до елемента 500 стає арифметикою
windowSize21Більше — менше порожніх ділянок, більше пам’яті. Менше — навпаки
initialNumToRender10Рівно стільки, щоб заповнити перший екран, — це шлях старту
maxToRenderPerBatch10Більші пакети заповнюють швидше й довше тримають потік JS на пакет
removeClippedSubviewstrue на AndroidВід’єднує позаекранні в’ю від нативної ієрархії; економить роботу, може давати артефакти

FlashList, список від Shopify, діє інакше: він перевикористовує. Замість монтувати й демонтувати рядки, він тримає приблизно екран клітинок і невеликий запас, а клітинку, що зникла вгорі, віддає елементу, який з’являється внизу. Версія 2, що вийшла 2025 року, працює лише на новій архітектурі й більше не потребує оцінок розміру. Її завантажують близько двох мільйонів разів на тиждень. З 10 вересня 2026 року вона несе ще й власний урок: Shopify йде з React Native і пише, що «веде переговори з кількома компаніями про довгострокове опікунство», — тож бібліотека, від якої ви залежите, тепер має спонсора, за яким треба стежити. Хоч який список, одиниця вартості — рядок. Список не зробить повільний рядок швидким: мемоїзуйте компонент рядка, тримайте його дешевим і давайте стабільний ключ.

Рядок 13 живе за тими самими правилами, що й React у вебі, — про них сторінка React: тримайте стан якомога нижче в дереві, мемоїзуйте те, що отримує незмінні пропси, дайте React Compiler мемоїзувати там, де його ввімкнено. Одне правило — суто мобільне. Навігаційний стек тримає змонтованими екрани під поточним, щоб вони зберігали позицію скролу й стан, — і вони так само перерендерюються щоразу, коли змінюється спільне сховище. freezeOnBlur у React Navigation зупиняє перерендери екранів, яких користувач не бачить; Coinbase 2020 року зробив те саме вручну, а розділ кейсів розповідає, чого їм коштувала відсутність цього.

Рядок 4 — це пам’ять, а не швидкість. Зображення декодують перед показом, і декодоване зображення займає ширина × висота × 4 байти, хоч яким був розмір файлу. Фото на 12 мегапікселів — 4000 на 3000 пікселів — займає в пам’яті 48 МБ, навіть якщо JPEG важив 2 МБ; стрічка з десяти таких — майже пів гігабайта, а на телефоні середнього класу з Android система вбиває застосунок задовго до цього. Просіть у сервера чи CDN той розмір, який справді показуєте, і беріть компонент зображень із дисковим і пам’яттєвим кешем, як-от expo-image.

Expo, нативний код і оновлення «по повітрю»

Expo колись був пісочницею, яку зрештою доводилося покидати. Тепер ні, і власна документація React Native радить починати новий застосунок із фреймворком і називає саме Expo. Він дає сервіс збірки, оновлення «по повітрю», великий набір підтримуваних нативних модулів, роутер на основі файлів і — те, що вирішує, як проєкт старітиме, — config plugins. Config plugin описує зміну нативних проєктів кодом: додати цей дозвіл, зареєструвати той . Теки ios та android тоді генеруються, а не правляться руками, тож оновлення їх перегенерує й накладе ваші зміни знову. Проєкт, чиї нативні теки правили руками, перетворює кожне оновлення на злиття з власними правками; саме такі проєкти через два роки досі сидять на три версії позаду.

Expo випускає SDK під кожну версію React Native, яку бере, — після того як перевірив бібліотеки разом. SDK 57, що вийшов 30 червня 2026 року, працює на React Native 0.86. SDK 58 у бета-версії з 15 вересня 2026 року на реліз-кандидаті 0.88 і стане стабільним невдовзі після 0.88. Для команди це і є практичний зміст «оновлюватися по одній версії»: по одному SDK, а npx expo install --fix вирівнює під нього кожну бібліотеку Expo.

Оновлення «по повітрю» та їхня точна межа

Оскільки логіка застосунку — це JavaScript, ви можете надіслати новий бандл уже встановленим застосункам без рев’ю магазину — це оновлення «по повітрю» (OTA). Виправлення доходить до користувачів за хвилини, а не за дні. Обидва магазини це дозволяють, у записаних межах. Угода Apple Developer Program License Agreement, розділ 3.3.1(B), каже: інтерпретований код можна завантажувати лише тоді, коли він не змінює основного призначення застосунку, не обходить підпис, пісочницю та інші механізми безпеки й не створює магазину для інших застосунків. Google Play забороняє завантажувати виконуваний код — файли .dex, JAR чи .so — звідки-небудь, крім Play, і робить виняток для коду, що працює у віртуальній машині чи інтерпретаторі, як-от JavaScript, — який однаково мусить відповідати всім іншим правилам Play.

Оновлення «по повітрю» замінює JavaScript-бандл і ресурси встановленого застосунку, але не його нативний код. Збірка 1.5 додала модуль камери, якого немає у збірці 1.4, а оновлення, написане під 1.5, кличе цей модуль. Розіслане всім, воно валить кожен телефон, що досі на 1.4. Runtime version в Expo — політика fingerprint рахує її автоматично з усього, що впливає на нативний код, — прив’язує кожне оновлення до збірок, для яких його зроблено, тож 1.4 його просто не отримує й чекає релізу в стор. Зміна нативного модуля, дозволу, версії React Native чи іконки завжди потребує нового бінарника й нового рев’ю.

Технічна межа суворіша за юридичну. Оновлення замінює JavaScript і ресурси — зображення, шрифти, тексти — і більше нічого. Усе, що змінює нативний код, потребує нового бінарника й нового рев’ю: додати бібліотеку з нативним модулем, змінити дозвіл, оновити React Native, змінити іконку. Небезпечний випадок — проміжний: оновлення, написане під новішу збірку, приходить на телефони зі старішою. JavaScript кличе нативний модуль, якого немає, і застосунок падає на старті. Expo запобігає цьому через runtime version — мітку нативного шару, яку несе кожна збірка й кожне оновлення, тож оновлення пропонують лише збіркам із тією самою міткою. Політика fingerprint рахує мітку з усього, що може вплинути на нативний код, — це надійніше, ніж піднімати її вручну й пам’ятати про це.

Релізи, оновлення й дедлайни магазинів на 2026 рік

React Native випускає мінорну версію — 0.86, 0.87 — приблизно що два місяці, і команда релізів підтримує три останні. Найновіша — «Active», із частими патчами; найстаріша з трьох — «End of Cycle», лише з виправленнями важливих регресій; усе старіше — «Unsupported». На практиці версію підтримують близько пів року. Від 0.83, з грудня 2025 року, приблизно кожен другий реліз планують без змін, що щось ламають для користувача, — такими були 0.83 і 0.86, — щоб темп було легше витримувати.

ВерсіяВихідСтатус на 2 жовт. 2026
0.89заплановано 7 груд. 2026Майбутня
0.88очікується 12 жовт. 2026Реліз-кандидат
0.8710 серп. 2026Active
0.869 черв. 2026Active
0.856 квіт. 2026End of Cycle — вийде з підтримки з виходом 0.88
0.84 і старші—Unsupported

Оновлюватися на одну мінорну версію — нудно й займає пів дня. Оновитися на чотири одразу — займає два тижні, бо фреймворк, бібліотека навігації, кожен нативний модуль і SDK обох платформ рухаються разом, і падіння після оновлення може прийти від будь-якого з них. React Native Upgrade Helper показує точний diff шаблону між будь-якими двома версіями — це більшість нативної роботи в «голому» проєкті. Таблиця релізів вище — ще й бюджет: пів року підтримки означає, що команда, яка оновлюється двічі на рік, ніколи не сидить на непідтримуваній версії, а та, що оновлюється раз на рік, — сидить завжди.

Який React Native перед вами

Що ви бачите в кодіЩо це означає
newArchEnabled=false у gradle.propertiesХтось відмовився від нової архітектури; з 0.82 цей прапорець ігнорується
import … from 'react-native/Libraries/…'Глибокий імпорт з часів до стабільного API 0.80; на 0.87 він перестає компілюватися
InteractionManager.runAfterInteractionsПрибрано в 0.87 — відкладену роботу плануйте інакше
react-native-code-pushCodePush з App Center, вимкнений 31 березня 2025 року, — OTA-каналу більше немає
JavaScriptCore як рушійПакет спільноти з 0.79; Hermes — типовий і перевірений шлях
Налагодження через віддалений дебагер ChromeПрибрано в 0.79; його замінили React Native DevTools
Правлені руками ios/ та android/ і жодного config pluginКожне оновлення — злиття; закладайте на це час або переходьте на згенеровані нативні проєкти

Дедлайни магазинів — успадковані від обох платформ

Кросплатформний застосунок не звільнений від календаря жодної з платформ — він має обидва. Кожен магазин піднімає мінімальні вимоги до збірок у визначену дату, і зміна доходить до React Native через нативні проєкти та через кожну нативну залежність. Ось ті, що діють або настають близько до дати цієї сторінки.

ДедлайнЩо вимагаєЩо це означає для застосунку на React Native
Apple, з 28 квіт. 2026Завантаження, зібрані в Xcode 26 з iOS 26 SDKНативні компоненти отримують вигляд Liquid Glass, намальовані з JS — ні; сам React Native 0.87 вимагає Xcode 26
Apple, застосунки, зібрані з iOS 27 SDKЖиттєвий цикл на сценах (UIScene), інакше застосунок не запуститься; ключ відмови від Liquid Glass ігноруєтьсяШаблон застосунку й кожен нативний модуль, що чіпляється за життєвий цикл, мають підтримувати сцени; Expo SDK 58 зроблено під iOS 27
Google Play, з 1 листоп. 2025 (відстрочки до 31 трав. 2026)Застосунки з target Android 15 і новіше підтримують сторінки пам’яті по 16 КБКожен файл .so у кожній нативній залежності має бути зібраний із вирівнюванням на 16 КБ; ядро React Native підтримує це з 0.77
Google Play, з 31 серп. 2026 (відстрочки до 1 листоп. 2026)Нові застосунки й оновлення мають target Android 16 (API 36)Edge-to-edge більше не вимкнути; predictive back увімкнено типово, а onBackPressed не викликається; на екранах від 600 dp блокування орієнтації ігнорується (тимчасова відмова діє до API 37)

Скільки насправді спільного — і яка нативна робота лишається

Обіцянка, яку чують, — одна кодова база на дві платформи. Чесна версія така: бізнес-логіка, мережа, стан і більшість екранів спільні, а решта — ні. Патерни навігації різні, жест «назад» є на одній платформі й немає на іншій, діалоги дозволів поводяться інакше, і кожен магазин має власні правила щодо того, що ви зобов’язані показати. React Native дає Platform.select і файли .ios.tsx / .android.tsx саме тому, що остання частина має розходитися.

АспектСпільне?Що це означає на практиці
Бізнес-логіка, API, станТак, повністюОсновна маса того, що ви пишете, — і причина, чому підхід узагалі окупається
Екрани й компонентиЗдебільшогоТой самий код із гілками платформи для відступів, заголовків і поведінки «назад»
Відчуття навігаціїЧастковоБібліотека це абстрагує; користувачі все одно чекають конвенцій своєї платформи
Дозволи, пуші, диплінкиНіНалаштовуються окремо, і кожен магазин перевіряє їх за своїми правилами
Віджети, застосунки для годинника, App Intents, Live ActivitiesНіПишуться нативно; React Native там не працює
Реліз і рев’юНіДва пайплайни, два набори сертифікатів, дві черги рев’ю — і обидва календарі дедлайнів вище

Коли для можливості немає JavaScript-, ви пишете нативний модуль — невеликий шматок Swift чи Kotlin, відкритий для JavaScript. Це нормально, а не провал підходу, але це мить, коли команді потрібен хтось, хто читає документацію платформи. Shopify після п’яти років перенесення кожного застосунку на React Native написав 2025 року, що «100% React Native має бути антиціллю»: віджети домашнього екрана, застосунки для годинника, моделі на пристрої й ярлики Siri краще будувати нативно. Команда React Native, де ніхто не розуміє нативного боку, зрештою впирається в задачу, до якої не дотягнеться жоден обсяг JavaScript.

П’ять кейсів і те, чого в кожному бракувало

Кожен кейс задокументували ті, з ким він стався: інженерні блоги, бюлетень безпеки, повідомлення постачальника про закриття. Разом вони покривають рішення взяти фреймворк, ціну перерендерів, зникнення хостингової залежності, інструменти розробки як поверхню атаки й рішення піти.

КейсЩо сталосяЧого бракувало
Airbnb, 2016–2018React Native усередині двох великих нативних застосунків; три платформи замість двох; нову роботу на React Native зупинено в червні 2018Рішення про межі — цілий застосунок чи окремий сценарій — і команда, що володіла містком
Coinbase, листоп. 2020Перемикання вкладок тривало понад секунду; кожен змонтований екран перерендерювався на кожну відповідь APIПідрахунок рендерів у міру додавання фіч; заморожені екрани поза видимістю
CodePush, 31 берез. 2025Microsoft закрив App Center, і разом із ним — OTA-сервіс, яким користувалися багато застосунків на React NativeПлан виходу для хостингової залежності
Metro4Shell, листоп. 2025 – лют. 2026CVE-2025-11953: дев-сервер слухав мережу й передавав запит в оболонку; експлуатація з 21 груд. 2025Дев-сервери лише на localhost; інструменти розробки оновлюють як продакшн-залежності
Shopify, 2020 – верес. 2026П’ять років перенесення всіх застосунків на React Native, потім повернення до Swift і KotlinНічого — змінилося припущення, на якому трималося рішення, і його перевірили знову

Перший кейс досі цитують у кожній розмові про React Native — і зазвичай хибно. У червні 2018 року Габріел Піл опублікував звіт Airbnb про два роки з React Native. Заголовком була продуктивність; суттю — структура. Airbnb додав React Native у два великі нативні застосунки, що й далі швидко змінювалися: 80 000 рядків продуктового коду на 220 екранах плюс 40 000 рядків інфраструктури на JavaScript — усередині застосунків, де на кожній платформі було приблизно вдесятеро більше коду й учетверо більше екранів. Щоб продуктова робота була можлива, інфраструктурна команда обгорнула для React Native мережу, експерименти, інтернаціоналізацію й анімовані переходи спільних елементів — і підтримувала ці обгортки в ногу з нативним кодом, що не переставав змінюватися. Їхніми словами, вони «зрештою підтримували код на трьох платформах замість двох». Вони також несли близько п’ятдесяти комітів, накладених поверх React Native, що робило кожне оновлення болісним, а час запуску середовища JavaScript шкодив стартовим екранам і диплінкам. Нову роботу на React Native зупинили, а найвідвідуваніші екрани запланували повернути в натив до кінця 2018 року. Більшість інженерів, що з ним працювали, досі оцінювали його добре. Урок — про межі, а не про швидкість.

Третій кейс — сервіс, який просто закінчився. CodePush, сервіс оновлень «по повітрю» від Microsoft, роками був типовим способом доставляти виправлення JavaScript у застосунки на React Native. Він жив усередині App Center, і 31 березня 2025 року Microsoft закрив App Center — а з ним і CodePush. Самостійний сервер, який Microsoft запропонував для власного хостингу, заархівували за два місяці. Команди, для яких OTA був частиною реагування на інциденти, втратили його в конкретну дату, а застосунок, чиї встановлені бінарники дивилися на старий сервіс, більше взагалі не міг отримувати виправлень — зрушити їх міг лише реліз у стор. Виправлення існувало завжди — оновлення від Expo чи сумісний сервіс, — але вимагало нативної зміни, а отже, рев’ю. План виходу з хостингової залежності дешево написати, поки сервіс іще працює.

Четвертий кейс атакував розробників, а не користувачів. 3 листопада 2025 року JFrog розкрив -2025-11953 з оцінкою 9,8 з 10 у @react-native-community/cli-server-api — пакеті, на якому працює дев-сервер Metro, що його запускає npx react-native start. Сервер слухав усі мережеві інтерфейси, а не лише машину розробника, і один із його ендпоїнтів передавав частину запиту у функцію, що відкриває файли й URL засобами операційної системи. Будь-хто, хто міг дістатися порту, виконував команди на комп’ютері розробника; на Windows — ще й із довільними аргументами. Версія 20.0.0 це виправила. VulnCheck бачив експлуатацію з 21 грудня 2025 року — так доставляли шкідливе ПЗ, — а 5 лютого 2026 року CISA додала вразливість до свого каталогу експлуатованих. Дев-сервер — це сервер: прив’язуйте його до localhost, тримайте подалі від недовірених мереж і оновлюйте інструменти так само вчасно, як залежності самого застосунку.

Де він вироджується

React Native щедрий там, де вебкоманда сильна, і мовчазний там, де вона слабка. Компоненти, стан і отримання даних переходять просто з React, тож екран будувати легко. Не переходять другий потік, нативні проєкти й календар магазинів — і майже кожен збій — одне з цього:

  • Анімації й ефекти скролу, керовані з JavaScript, що смикаються тієї миті, коли в потоку з’являється справжня робота (рядки 8–9).
  • Довгі списки через .map() або віртуалізовані списки з дорогими немемоїзованими рядками (рядок 10).
  • Глобальне сховище, що на кожну зміну перерендерює кожен змонтований екран (рядок 13).
  • Фото в повній роздільності, декодовані в пам’ять заради мініатюр (рядок 4).
  • Правлені руками теки ios та android, що перетворюють кожне оновлення на конфлікт злиття.
  • Версія, що відстала більш ніж на три мінорні, і нативні бібліотеки, які так і не мігрували на нову архітектуру.
  • Оновлення «по повітрю» без runtime version, поетапного розгортання й відкату.
  • Команда без нативних навичок, що стає першого ж разу, коли фічі потрібен модуль, віджет чи дедлайн магазину.
  • Тестування лише на свіжому iPhone, де потік JavaScript достатньо швидкий, щоб приховати всі помилки вище.
  • Дев-сервер, доступний з мережі.

Чесна межа — другий потік і друга платформа. Продукт, чия суть — безперервна власна графіка (гра, інструмент для малювання, конвеєр камери), бореться з архітектурою, бо його гарячий шлях хоче жити повністю по один бік переходу. Продукт, збудований навколо можливості, яка не має JavaScript-поверхні й змінюється з кожним релізом ОС, однаково живе в нативному коді. І економіка не стала: React Native окупається, коли одна спільна реалізація економить більше, ніж коштує шар фреймворку, а рішення Shopify 2026 року показує, що цей баланс може зрушити. Для форм, списків, стрічок, комерції й робочих застосунків, які будує команда, що вже пише на React, — тобто для більшості того, що будують, — це досі дуже вигідний обмін.

Практична перевірка займає десять хвилин. Прочитайте версію React Native у package.json і знайдіть її рядок у таблиці релізів. Складіть список нативних залежностей і перевірте в кожної підтримку нової архітектури й дату останнього релізу. Відкрийте найповільніший екран у release-збірці на телефоні середнього класу з Android з увімкненим монітором продуктивності. Знайдіть у коді useNativeDriver: false, обробники onScroll, що викликають setState, і .map( усередині ScrollView. Переконайтеся, що оновлення «по повітрю» несуть runtime version. І звірте target API для Android і версію Xcode з таблицею дедлайнів.

Коли це застосовувати

Застосовуйте, коли

  • Продукт, якому потрібні обидві платформи, а будує його команда, що вже пише на React і .
  • Контентні, комерційні та робочі застосунки — форми, списки, навігація, мережа, — тобто більшість того, що будують.
  • Продукти, яким вигідно доставляти виправлення без черги рев’ю — у межах оновлень «по повітрю».
  • Команди, яким потрібні справжні в’ю платформи — і власні редизайни платформи, — а не їхнє відтворення.

Уникайте, коли

  • Ігри, інструменти для малювання й усе, що тримається на безперервній власній графіці, — це боротьба з архітектурою.
  • Застосунки навколо можливості платформи, що не має JavaScript-поверхні й змінюється з кожним релізом ОС.
  • Однаплатформний продукт, де абстракція коштує вам і нічого не повертає.
  • Команди без ресурсу на два релізні пайплайни й два календарі магазинів: спільний код, а не постачання.

Джерела й метод

На чому стоїть ця стаття

  • 15 джерел
  • 2 задокументовані збої
  • Перевірено 13 жовтня 2026 р.

Дослідження з Claude. Пошук і звірку першоджерел зроблено з Claude (Anthropic). Відбір, текст і перевірку фактів — редакція Anatomy of IT Product.

Було корисно?

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