Головна / Статті

Flutter проти React Native: рішення, які проявляються лише у продакшені

Реалістичне порівняння Flutter та React Native, яке ігнорує суперечки щодо тестів продуктивності та зосереджується на відображенні контенту, мові програмування, стані даних, списках та екосистемі у міру розвитку додатку.

Видавець: REACTAPP.TOP8 хв читання1792 слів

Джерела: Flutter vs React Native: The Real Differences Start After “Hello World”

Flutter та React Native обіцяють одне й те саме: написати один кодовий базис, випустити додаток для Android та iOS та припинити підтримувати два окремі нативні додатки. На папері пропозиції ідентичні, і для першого екрана додатку це справді так. Створення кнопки, відображення списку, налаштування навігації чи показ відповіді API є простим у будь-якому з цих фреймворків. Різниці, які насправді впливають на проект, там не проявляються. Вони з’являються тоді, коли додаток розвивається з використанням індивідуального інтерфейсу, анімацій, управління станом, інтеграції з нативними технологіями та багаторічної підтримки. Це порівняння того, що починає відрізнятися після демонстрації, щоб ви могли обрати на основі того, як кожен фреймворк працює у масштабі, а не лише швидкості відображення „Hello World“.

Перше враження навмисно схоже

Обидві платформи пропонують швидкий шлях до запущеного додатку. Ви можете створювати екрани, додавати навігацію, викликати API, відображати списки та обробляти дані користувача, не розділяючи код на дві окремі бази. Саме ця спільна продуктивність є причиною, чому команди звертаються до міжплатформних інструментів. Простий екран виглядає майже однаково незалежно від обраної платформи. Лише коли додаток стає складнішим, ці дві філософії починають розходитися, тому чесне порівняння відбувається саме у складних частинах, а не у початкових шаблонах.

Flutter працює з віджетами

Найбільша помітна відмінність у Flutter полягає у тому, що майже все, з чим ви працюєте, є віджетом. Екрани, кнопки, відступи навколо них та макетування, яке їх розташовує, — усе це віджети, так само як і багато структур, які ніколи не відображають нічого видимого на екрані. Тут колонка складається з позначки, невеликого проміжку та кнопки, причому кожен елемент є окремим віджетом, розташованим усередині ієрархічної структури.

Column(
  children: [
    Text('Welcome'),
    SizedBox(height: 16),
    ElevatedButton(
      onPressed: () {},
      child: Text('Continue'),
    ),
  ],
)

Як тільки обирається така модель, створення інтерфейсу користувача стає надзвичайно послідовним: маленькі віджети комбінуються у більші, а ті з часом перетворюються на цілі екрани. React Native обирає інший підхід. Він описує інтерфейс користувача за допомогою компонентів React, написаних на JavaScript чи TypeScript, тож когнітивна модель по суті полягає у створенні додатку на React, що здається цілком природним для тих, хто вже працює з React. Жодна з цих моделей не є універсально кращою. Вони просто змушують нас думати про створення інтерфейсу в різних термінах, а „правильний“ варіант сильно залежить від того, які інстинкти вже є у вашій команді.

Відображення та ступінь контролю над інтерфейсом користувача

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

React Native також може створювати дуже індивідуалізовані інтерфейси, але робить це іншим способом, оскільки традиційно працює з власними нативними компонентами платформи через свою архітектуру часу виконання. Варто бути точними тут: сучасний React Native значно змінився завдяки своїй Новій архітектурі, тож старий вираз „JavaScript спілкується з нативним кодом через міст“ більше не описує того, як насправді працює поточна версія, а порівняння, що ґрунтуються на ньому, є застарілими. Справжня проблема не в тому, що одна з фреймворків не здатна створити певний інтерфейс — обидва можуть це зробити. Різниця полягає у шляху, який кожен з них обирає для досягнення цілі, та у тому, як цей шлях впливає на щоденну роботу.

Dart проти JavaScript та TypeScript

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

final String name = 'Ankit';
final int age = 25;

Така статична типізація полегшує розуміння більших кодових баз, оскільки компілятор виявляє цілі категорії помилок ще до їх виконання. Команди React Native часто вдаються до TypeScript, щоб отримати таку саму перевагу у світі JavaScript.

const name: string = 'Ankit';
const age: number = 25;

TypeScript забезпечує сильну типізацію, залишаючись частиною екосистеми JavaScript, і це справжня перевага для організацій, які вже інвестували у JavaScript. Компанія з уже сформованою командою для розробки веб-пристроїв на React часто може легше впровадити React Native, оскільки розробники можуть використовувати існуючі концепції, інструменти та звички. Для команди, яка повністю присвячена Dart, Flutter пропонує зосереджене, самодостатнє середовище. Компроміс полягає у широті існуючої екосистеми проти цілісності спеціалізованої.

Керування станом більше не є простим завданням

Стан — це те, де рання простота зникає найшвидше. Маленький додаток має кілька елементів стану; продакшн-додаток накопичує довгий список таких елементів, зокрема статус автентифікації, дані профілю користувача, вміст кошика, статуси завантаження API, функції сторінкування, фільтри пошуку, сповіщення, налаштування теми, локальне зберігання, стан форми та оновлення в реальному часі. Коли існує стільки проблем одночасно, сама лише фреймворк вже не є рішенням. Вам потрібна архітектура та ретельно продумана стратегія управління станом, яка буде діяти на її основі.

Обидві екосистеми пропонують різні варіанти. У Flutter є Provider, Riverpod, BLoC, Cubit, GetX та інші; у React Native – Redux, Zustand, MobX, Context API та багато іншого. Кількість пакетів тут мало що говорить. Ключовим фактором для забезпечення підтримки є здатність вашої команди послідовно структурувати та розвивати стан додатку з часом. Фреймворк може забезпечувати відмінну продуктивність інтерфейсу, але все одно створювати додаток, який важко підтримувати, якщо архітектура стану є слабкою. Та сама дисципліна, яка зберігає цілісність архітектури великого React-додатку, застосовується тут незалежно від того, який фреймворк відображає зміст.

Продуктивність – це не числовий показник

Продуктивність — це найбільш часто обговорювана тема у цьому порівнянні. Статті регулярно стверджують, що одна фреймворк-система швидша за іншу, ґрунтуючись на синтетичних тестах, але реальні додатки — це не тести. Продакшн-додаток зазвичай поєднує мережеві запити, великі списки, зображення, анімації, карти, локальне зберігання, фонову роботу, сповіщення типу push, веб-вікна, інструменти аналітики, нативні SDK та пакети від сторонніх розробників, і кожен з цих елементів може вплинути на продуктивність додатку.

Погано створений додаток на Flutter може працювати повільно, так само як і погано створений додаток на React Native. Непотрібні перебудови, надмірне відтворення змісту, занадто великі зображення, неефективні списки, ресурсомісткі обчислення, необережне використання пам’яті та погано спроєктовані мережеві процеси спричиняють уповільнення роботи, незалежно від назви фреймворку. Більш корисним є запитання про те, наскільки добре архітектура додатку справляється з його конкретним навантаженням, а не про те, який фреймворк перемагає у абстрактній гонці. Відповідь на запитання „який швидший“ майже не має сенсу без знання того, що саме ви створюєте.

Списки уточнюють суть

Уявімо додаток для електронної комерції з тисячами товарів. Завантажувати кожен товар у пам’ять та відображати їх усі одночасно — це помилка в будь-якому фреймворку. Рішенням Flutter є механізм будування елементів за потребою, коли вони з’являються у полі зору.

ListView.builder(
  itemCount: products.length,
  itemBuilder: (context, index) {
    return ProductCard(
      product: products[index],
    );
  },
)

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

Екосистема є справжнім вирішальним фактором

React Native має явну перевагу в одному конкретному аспекті: він існує всередині екосистеми JavaScript. JavaScript та TypeScript вже є скрізь — у фронтенді, бекенді, інструментах та в Інтернеті, а React належить до найпоширеніших бібліотек користувацького інтерфейсу. Тож організації з сильними командами, які працюють з React, мають природний шлях до використання React Native, можучи повторно використовувати навички та бібліотеки, від яких вони вже залежать.

Перевага Flutter є протилежною. Він пропонує відносно зосереджену екосистему, орієнтовану на Flutter та Dart, що може здатися особливо послідовною для команд, які воліють створювати мобільні додатки, не спираючись на широкий світ JavaScript. Жоден з них не є абсолютно кращим; кращий вибір залежить від того, яка у вас вже є команда.

То який варіант вибрати?

Не існує універсального переможця, а правильне рішення залежить від особливостей проекту та команди. Якщо у команди вже є значний досвід роботи з React та TypeScript, React Native легко інтегрується в їхню існуючу технологічну структуру. Якщо команда прагне спеціалізованої міжплатформенної фреймворк для інтерфейсу, створеної на основі Dart та моделі з використанням віджетів, Flutter є ідеальним вибором. Додаток, який залежить від накопиченого досвіду команди у роботі з React та її інфраструктури на JavaScript, є переконливим аргументом на користь React Native; додаток, який вимагає сильно налаштованого інтерфейсу, створеного фахівцями, які вже знайомі з Flutter, — це переконливий аргумент на користь останнього. Помилкою, яку слід уникати, є вибір фреймворку лише через те, що якась стаття назвала його „кращим“, а не через те, що він підходить для конкретного продукту.

Підсумок

Flutter та React Native підходять до однієї й тієї самої загальної проблеми з різних напрямків. Flutter пропонує модель, засновану на віджетах та мові Dart, разом із щільно інтегрованим набором інструментів для створення користувацького інтерфейсу, який чудово підходить для індивідуального дизайну. React Native впроваджує екосистему React та JavaScript у мобільні додатки, надаючи доступ до можливостей нативної платформи завдяки архітектурі, яка значно розвинулася за межі своєї початкової репутації як мосту між технологіями. Жоден з варіантів за замовчуванням не робить кожен додаток кращим. Правильне питання не полягає у тому, „яка фреймворк перемагає“, а у тому, „яка фреймворк підходить для цього продукту, цієї команди та цього типу додатку“. Майже будь-що може відобразити перший екран; саме у всьому, що йде далі, ці дві фреймворки справді відрізняються.