Міграція мобільного застосунку з React Native на Flutter
Міграція з React Native на Flutter — це не портування екранів один до одного. Це переосмислення архітектури: інша мова (Dart замість JavaScript/TypeScript), інша модель рендеринга (Skia/Impeller замість нативних компонентів), інші паттерни керування станом. Проект на 50 екранів з Redux та react-navigation не перетворюється в Flutter-застосунок за два тижні.
Робимо такі міграції поступово або повним переписуванням — залежить від розміру проекту та критичності безперервності роботи.
Чому це складніше, ніж здається
Немає прямого аналога компонентів. У React Native FlatList з keyExtractor, renderItem та getItemLayout — це звична конструкція. У Flutter ListView.builder працює схоже, але SliverList з SliverChildBuilderDelegate — зовсім інший рівень. Розробники, які прийшли з RN, часто використовують Column + SingleChildScrollView там, де потрібен CustomScrollView зі Slivers — і отримують jank на довгих списках.
Навігація. У React Native екосистема навігації живе в react-navigation з добре знайомою концепцією Stack, Tab, Drawer. У Flutter офіційний шлях — Navigator 2.0 з Router та RouteInformationParser, що концептуально складніше. На практиці переходимо на go_router (рекомендовано Flutter team): він дає декларативну навігацію з deep linking та типізованими параметрами. Перенесення структури навігації — окрема задача, яку не можна автоматизувати.
Нативні модулі. У React Native кастомні нативні модулі написані на Java/Kotlin та Objective-C/Swift через міст. У Flutter — це Platform Channels: MethodChannel, EventChannel, BasicMessageChannel. Семантика та ж, реалізація інша. Якщо в RN-проекті є кастомні модулі (Bluetooth, NFC, специфічне залізо), їх потрібно переписати під Flutter Platform Channels або знайти Flutter-плагін у pub.dev.
Керування станом. Redux → Bloc/Cubit — концептуально близько (однонаправлений потік даних, actions/events, reducers/states). Але кодової автоматичної конвертації немає. MobX → Riverpod або Provider — складніше, тому що реактивна модель MobX не має прямого аналога. Riverpod 2.x з аннотаціями @riverpod — гарний вибір для команд, які цінують compile-time safety.
Як проводимо міграцію
Аудит та інвентаризація. Перший крок — повна карта проекту: список екранів, нативні залежності, сторонні SDK (аналітика, платежі, карти), кастомні нативні модулі. Для кожної RN-залежності знаходимо Flutter-аналог або визначаємо, потрібно ли писати Plugin самостійно.
| React Native | Flutter-аналог |
|---|---|
| react-navigation | go_router |
| redux / redux-toolkit | bloc / cubit |
| react-query | riverpod + dio |
| react-native-mmkv | shared_preferences / hive |
| react-native-reanimated | flutter_animate / rive |
| react-native-maps | google_maps_flutter |
| react-native-camera | camera / image_picker |
| react-native-purchase | purchases_flutter (RevenueCat) |
Стратегія поетапної міграції. Для великих проектів (30+ екранів) використовуємо Add-to-App підхід: Flutter-модуль вбудовується в існуючий RN-застосунок через FlutterEngine. Екрани мігрують один за одним, поки весь проект не виявиться на Flutter. Це дає можливість тестувати кожен мігрований модуль у продакшені до повного переходу.
Для невеликих проектів (до 20 екранів) — повне переписування швидше та чистіше. Паралельна розробка нового Flutter-застосунку з поступовим QA.
Dart та типізація. TypeScript-розробники адаптуються до Dart швидко: статична типізація, null safety (починаючи з Dart 2.12), async/await, generics — все знайоме. Особливість, яка дивує: у Dart немає ключового слова interface, будь-який клас можна імплементувати. І required іменовані параметри — обов'язкова практика для читаних віджетів.
Тестування. Flutter надає три рівні: unit-тести (flutter_test), widget-тести (рендеринг віджетів без пристрою), integration-тести (пакет integration_test, запускається на реальному пристрої або симуляторі). Покриття критичної бізнес-логіки unit-тестами переносимо разом з кодом — це страховка при міграції.
Що впливає на терміни
Лінійна залежність від кількості екранів працює тільки для простих CRUD-форм. Реальні множники:
- кастомні нативні модулі — +2–5 днів кожен
- складна анімація (react-native-reanimated → rive/flutter_animate) — +1–3 дня на екран
- платіжні інтеграції (In-App Purchase, Stripe) — +3–7 днів
- карти з кастомними маркерами та геолокацією — +4–8 днів
- настройка CI/CD під Flutter (Fastlane, GitHub Actions) — +2–3 дня
Типовий проект на 20–30 екранів без складної нативної логіки: 6–12 тижнів. Вартість розраховується після аудиту кодової бази та складання повного списку залежностей.







