React Native
React Native — це React, який рендерить справжні в’ю платформи замість вузлів DOM. Це не вебв’ю і не компілятор у Swift чи Kotlin: ваш JavaScript виконується у власному рушії й каже платформі, що показати на екрані. Саме ця архітектура дозволяє вебкоманді випустити справжній мобільний застосунок — і саме вона породжує всі питання продуктивності до фреймворку. На цій сторінці — модель потоків, Expo, нативні модулі й те, де ілюзія ламається.
- В’ю
- Справжні в’ю платформи
- Ваш код
- Один потік JS
- Спільно
- Логіка, не весь інтерфейс
Що насправді на екрані
<View> у React Native — це не div і не малюнок. Він стає справжнім UIView на iOS і справжнім android.view.View на Android, який створює й малює платформа. Тому скрол має правильну фізику, клавіатура поводиться коректно, а застосунок безкоштовно успадковує доступність: нічого з цього не переписано — це операційна система робить свою роботу.
Ваш JavaScript тим часом виконується в окремому рушії — тепер типово це Hermes — у власному потоці. Він ніколи не торкається цих в’ю напряму. Він описує, який вигляд має мати дерево; цей опис перетинає межу на нативний бік, третій потік міряє розкладку, а головний потік застосовує результат. Раз подивитися на схему цього вартує більше за будь-який список порад з оптимізації, бо кожна проблема продуктивності в React Native — це питання про той перехід.
Початковий задум серіалізував кожне повідомлення через цю межу як JSON і надсилав пакетами — це й був «міст». Він працював і породив фірмовий збій фреймворку: коли потік JavaScript зайнятий, нативний бік отримує вказівки пізно, і кадри втрачаються. Нова архітектура це замінює. JSI дозволяє JavaScript тримати пряме посилання на нативний об’єкт і викликати його синхронно, Fabric перебудовує на цьому рендеринг, а TurboModules завантажують нативні модулі ліниво, а не всі на старті.
Expo і чому починати варто з нього
Expo колись був пісочницею, яку зрештою доводилося покидати. Тепер це не так, і порада справді змінилася: починайте новий проєкт на React Native з Expo, якщо немає конкретної причини цього не робити. Він дає керований сервіс збірки, оновлення «по повітрю», великий набір підтримуваних нативних модулів і — найважливіше — config plugins, які описують зміни в нативному проєкті кодом, а не правками руками, що губляться при наступному оновленні.
Саме цей пункт вирішує, як проєкт старітиме. «Голий» React Native-застосунок містить теки ios та android, які ви правите напряму, і кожне оновлення фреймворку перетворюється на злиття зі зміненими вами файлами. З config plugins ці теки генеруються, тож оновлення їх перегенерує, а ваші налаштування накотяться заново. Команди, що правлять нативні проєкти руками, — це ті самі, що через два роки досі сидять на три мажорні версії позаду.
Як це виявляється в реальній поставці
Повторювана скарга на продуктивність — це списки. Довгий список, відрендерений через map, будує кожен рядок незалежно від того, чи він на екрані, а на середньому Android-телефоні це різниця між застосунком, що відчувається нативним, і тим, що ні. Беріть віртуалізований список, дайте йому стабільний keyExtractor, мемоїзуйте компонент рядка й тримайте висоти рядків передбачуваними. Майже кожна заява «React Native повільний» зводиться до списку, зайвого перерендеру або зображення, якому ніколи не змінювали розмір.
Друге, що варто планувати заздалегідь, — оновлення. React Native рухається швидко, і екосистема навколо рухається разом із ним, тож проєкт, який рік пропускає версії, стикається з оновленням, де фреймворк, бібліотека навігації, нативні модулі й SDK платформ їдуть одночасно. Оновлюватися по одній мінорній версії — нудно й займає пів дня; оновитися одразу на чотири — займає два тижні й ламає речі, причину яких ніхто не встановить.
Де це вироджується
- Анімації, керовані з JavaScript, смикаються тієї миті, коли потік має справжню роботу.
- Довгі списки через
mapзамість віртуалізованого списку рендерять рядки, яких ніхто не побачить. - Правлені руками теки
iosтаandroidперетворюють кожне оновлення фреймворку на конфлікт злиття. - Одна розкладка на обидві платформи без огляду на їхні конвенції навігації.
- Команда взагалі без нативних навичок стає першого ж разу, коли фічі потрібен модуль.
- Тестування лише на свіжому iPhone, де потік JS достатньо швидкий, щоб приховати всі помилки вище.
- Розрахунок на OTA-оновлення для змін, що зачіпають нативний код: так їх не доставити.
Коли це застосовувати
Застосовуйте, коли
- Продукт, якому потрібні обидві платформи, а команда вже пише React і TypeScript.
- Контентні, комерційні та робочі застосунки — форми, списки, навігація, мережа, — тобто більшість того, що будують.
- Продукти, яким вигідно доставляти виправлення без черги рев’ю — у межах того, що може нести OTA.
- Команди, яким потрібні нативні в’ю та нативна доступність, а не їх відтворення.
Уникайте, коли
- Застосунки з важкою графікою, ігри й усе з безперервною власною анімацією — це боротьба з архітектурою.
- Застосунки навколо можливості платформи, що не має JavaScript-поверхні й змінюється з кожним релізом ОС.
- Однаплатформний продукт, де абстракція коштує вам і не повертає нічого.
- Команди без ресурсу тримати два релізні пайплайни: кросплатформним є код, а не постачання.
Було корисно?
Поділіться з тим, хто працює над тією ж задачею.