Миграция мобильного приложения с 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 через bridge. Во 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 недель. Стоимость рассчитывается после аудита кодовой базы и составления полного списка зависимостей.







