«С чего начать, чтобы не переписывать проект через полгода?» Короткий ответ — с минимума инструментов и осознанных решений, а не с готовых «правильных» стеков из туториалов. Ниже — пять вещей, которые джуну реально экономят недели работы. Это не «секретные приёмы», а компромиссы, которые опытные разработчики уже сделали, — и не очень любят про них рассказывать на собеседованиях.
Сразу важная оговорка. Статья — для тех, кто пишет первое-второе приложение на React Native и собирается выкатывать его в стор. Если у вас уже год коммерческого опыта или вы пилите ресёрч-прототип — большую часть советов можно пропустить. Мы не разбираем установку окружения, основы JSX и базу JavaScript — об этом написаны сотни материалов, повторяться не стоит.
1. Начинайте с Expo, а не с bare React Native
Тезис: в 2026 году Expo закрывает 90% задач коммерческого приложения. Идти сразу в чистый RN — добровольно купить себе неделю настройки Xcode, Gradle и подписей.
Почему так. Expo SDK 53+ поддерживает практически любые нативные модули через config plugins, а команда npx expo prebuild в любой момент превращает Expo-проект в обычный нативный — без потерь и переписывания. То есть выбор «Expo vs bare» больше не финальный, это просто стартовая точка.
Цифры:
- Запуск нового проекта с Expo: 5–10 минут до билда на устройстве.
- Запуск bare RN с нуля: 2–6 часов первой настройки на macOS, дольше на Windows (Xcode требует Mac).
- Размер пустого APK с Expo: 25–35 МБ, что близко к bare RN (20–30 МБ) — миф «Expo раздувает приложение» давно неактуален.
На практике. Сложности с Expo начинаются, когда нужен сильно кастомный нативный модуль, которого нет в экосистеме, или интеграция, требующая правки самого нативного шаблона (например, специфическая работа с фоновыми задачами на iOS). В этом случае делаете expo prebuild и продолжаете работать в нативном проекте — без переезда репозитория.
Подведём черту. Начните с Expo, дойдите до прод-релиза, и только когда упрётесь в реальное ограничение — переключайтесь. Так вы не платите за гибкость, которая, скорее всего, не понадобится.
2. FlatList вместо ScrollView — с самого первого списка
Тезис: ScrollView с .map() — главный источник лагов в RN-приложениях новичков. FlatList решает проблему почти одной строчкой, но только если её правильно готовить.
Почему так. ScrollView рендерит все дочерние элементы сразу при монтировании. Сто карточек — сто отрендеренных компонентов в памяти. FlatList виртуализирует: на экране живут только видимые элементы плюс небольшой буфер, остальные размонтированы.
Цифры:
- На списке из 500 элементов ScrollView держит в памяти все 500 компонентов; FlatList — обычно 10–20.
- Время до интерактивности на длинном списке: у ScrollView оно растёт линейно с числом элементов, у FlatList остаётся практически постоянным.
Минимальный рабочий вариант:
item.id}
renderItem={({ item }) => }
initialNumToRender={10}
/>
На что обратить внимание сразу. keyExtractor должен возвращать стабильный идентификатор — не индекс массива, иначе при обновлении данных компоненты перерисуются заново. Для одинаковых по высоте элементов добавьте getItemLayout — это убирает «прыжки» при быстром скролле. Если данных тысячи или элементы тяжёлые, посмотрите в сторону @shopify/flash-list — drop-in замена с более агрессивной переработкой ячеек.
Подведём черту. Используйте ScrollView только для содержимого, которое заведомо помещается на один-два экрана. Всё остальное — FlatList или FlashList.
3. Hermes включён по умолчанию — не выключайте и замеряйте
Тезис: Hermes (JS-движок от Meta для RN) включён по умолчанию с версии 0.70 и снижает время старта приложения. Большинство джунов про него вообще не думают — и зря.
Почему так. Hermes компилирует JS в байткод на этапе сборки, а не парсит на устройстве при запуске. Это особенно заметно на бюджетных Android-устройствах, которыми пользуется значимая часть аудитории.
Цифры:
- Время до интерактивности (TTI, time-to-interactive) на холодном старте: с Hermes — обычно на 20–30% быстрее JSC на средних Android.
- Размер APK: Hermes добавляет ~3–5 МБ, но за счёт упакованного байткода итог часто меньше, чем у JSC-сборки.
- Потребление памяти: на сценариях со средней нагрузкой Hermes даёт экономию 10–30%.
Что с этим делать. Убедитесь, что в android/app/build.gradle стоит hermesEnabled: true (для Expo проверять не нужно — он включён). Замеряйте старт через встроенный Perf Monitor (Cmd+D / Cmd+M → Show Perf Monitor) или через React Native DevTools. Если видите TTI больше 3 секунд — сначала разберитесь, что грузится синхронно при старте, и только потом ищите проблему в коде экранов.
Подведём черту. Hermes — самый дешёвый прирост производительности в RN. Бесплатно — оставьте включённым и научитесь его измерять.
4. Платформенные различия закладывайте с первого экрана
Тезис: «Один код — два приложения» в React Native — это маркетинговый слоган. На практике iOS и Android расходятся в десятках мелочей, и закладывать это в архитектуру нужно с первого экрана, а не вечером перед релизом.
Что чаще всего ломается:
- Безопасные зоны. На iPhone с челкой или Dynamic Island контент уезжает под статус-бар. Используйте
react-native-safe-area-context(SafeAreaProvider+useSafeAreaInsets), а не отступы «на глаз». - Клавиатура. На iOS она накрывает поля ввода, на Android обычно поджимает контент. Решается через
KeyboardAvoidingViewс разнымиbehaviorдля каждой платформы. - Шрифты. На iOS подключение кастомного шрифта — это
Info.plist, на Android — XML и точные имена файлов. С Expo проще черезexpo-font. - Тени. На iOS —
shadowColor / shadowOffset / shadowOpacity / shadowRadius. На Android — толькоelevation. Кросс-платформенно тени не работают без обёртки. - Хаптика, разрешения, deep links — настраиваются по-разному, и это нормально.
Цифры: в коммерческом приложении средней сложности доля платформо-специфичного кода обычно 5–15%. Это нормально, и не нужно бояться Platform.OS === 'ios' — главное собирать такую логику в одном месте, а не размазывать по экранам.
Простой приём:
const styles = StyleSheet.create({
card: {
...Platform.select({
ios: {
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
},
android: { elevation: 3 },
}),
},
});
Подведём черту. Не ищите «универсальное решение» там, где платформы расходятся осознанно. Закладывайте развилку явно — это короче и понятнее, чем потом разбирать, почему на Android всё некрасиво.
5. Не тащите Redux в проект на старте
Тезис: Redux Toolkit — хороший инструмент, но не для первого приложения и не «потому что так на собеседованиях спрашивают». Большинству джунов он нужен в момент, когда состояние уже превратилось в кашу, — а до этого момента можно дойти иначе.
Почему так. У Redux есть фиксированная цена входа: сторы, слайсы, селекторы, мидлвары, типизация. На приложении из 5–10 экранов это в 2–3 раза больше кода, чем нужно.
Разумный путь развития состояния:
useState+useReducer— для всего, что живёт внутри одного экрана.- Context API — для тем, локалей, текущего пользователя. То, что меняется редко и нужно везде.
- Zustand или Jotai — когда контекста становится много и появляются «прокидывания через четыре уровня». Zustand даёт глобальный стор в пять строк кода, без бойлерплейта.
- TanStack Query (бывший React Query) — для серверного состояния: запросы к API, кеши, повторы. Это закрывает 80% задач, под которые джуны обычно зовут Redux.
- Redux Toolkit / Effector — только когда у вас сложная синхронизация между несколькими источниками данных и нужны строгие правила обновления.
Цифры: на приложении из 8 экранов связка «Context + TanStack Query + Zustand» обычно занимает 150–250 строк инфраструктурного кода. Аналогичная функциональность на Redux Toolkit — 400–700 строк с типами.
«Без Redux серьёзное приложение не сделать» — миф. Большое количество продакшен-приложений, включая многие из топа сторов, живут без Redux вообще. Выбор инструмента — не вопрос статуса, а вопрос задачи.
Подведём черту. Берите минимальный стек, который закрывает текущую задачу. Если упрётесь — переедете. Это дешевле, чем заранее закладывать сложность под несуществующие проблемы.
Итог
Если свести пять пунктов в один: начинайте с инструментов, которые легко выбросить, измеряйте то, что критично, и не имитируйте сложность взрослых проектов. Конкретно — Expo как старт (5–10 минут до билда вместо нескольких часов настройки), FlatList с первого списка (10–20 компонентов в памяти вместо сотен), Hermes по умолчанию (TTI на 20–30% быстрее), платформенные различия в архитектуре с первого экрана (5–15% кода — это нормально), состояние от простого к сложному (150–250 строк против 400–700). На приложении из 5–10 экранов этот набор даёт быстрый старт за 1–2 недели до прод-сборки и оставляет пространство для роста, когда задача усложнится.
Что почитать дальше
Хороший способ перейти от «работает на эмуляторе» к «работает у пользователей» — посмотреть, как устроены реальные коммерческие приложения. Мы регулярно разбираем кейсы и архитектурные решения готовых решений для розницы в блоге MobiusApp — там же лежат материалы о стоимости, сроках и интеграциях, если в какой-то момент решите делать приложение не в одиночку.