Как выстроить архитектуру крупного приложения на React Native?

Построение архитектуры крупного приложения на React Native требует системного подхода к организации кода, разделению ответственности, масштабируемости, производительности и удобству поддержки. Нельзя опираться только на шаблон App.js — важно заранее продумать структуру директорий, модели данных, управление состоянием, бизнес-логику, работу с API, кэширование, навигацию, переиспользуемые компоненты и подход к тестированию.

Структура директорий

Один из вариантов модульной архитектуры (Feature-Sliced или Domain Driven Design-подобной):

/src
/app
navigation/
theme/
store/
config/
constants/
/features
/auth
components/
screens/
services/
hooks/
slices/
/profile
...
/entities
/user
model/
types/
services/
/shared
/ui
/hooks
/utils
/components
/api
  • app/ — инициализация и глобальные зависимости

  • features/ — пользовательские функции (регистрация, авторизация, загрузка постов)

  • entities/ — абстракции домена (User, Post), без конкретной бизнес-логики

  • shared/ — переиспользуемые элементы

  • Каждый слой можно изолировать и переиспользовать

Навигация

Использование react-navigation с разделением по типам навигации:

NavigationContainer
└── RootNavigator
├── AuthStack
 └── LoginScreen
└── MainStack
├── BottomTabs
└── Screens
  • Использовать вложенные навигаторы (stack внутри tabs, tabs внутри drawer)

  • Сохранение навигации в navigation/ (например, index.ts, routes.ts, linking.ts)

  • Конфигурация экранов по ролям или модулям

Состояние (State Management)

В крупных приложениях важно чётко разграничить:

  • Локальное состояние (useState, useReducer)

  • Состояние компонента (form, modal open)

  • Глобальное состояние (пользователь, токен, настройки)

Выбор инструментов:

  1. **Redux Toolkit + RTK Query
    **

    • Удобно масштабируется

    • Инкапсуляция API-логики и кэширования

    • Поддержка middleware

    • createSlice, createAsyncThunk

  2. **Zustand
    **

    • Минималистичная альтернатива Redux

    • Подходит для глобального состояния

  3. **React Context
    **

    • Только для небольшого глобального состояния (например, тема, язык)
  4. Jotai, Recoil — альтернатива с атомарной структурой данных

Работа с API

Использование слоя абстракции для сетевых запросов:

  • axios с интерсепторами

  • fetch + обёртка с логами и авторизацией

  • RTK Query или React Query для кэширования, автоматических повторов, фетчинга

Пример: src/shared/api/userApi.ts

import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
export const userApi = createApi({
reducerPath: 'userApi',
baseQuery: fetchBaseQuery({ baseUrl: '/api/' }),
endpoints: (builder) => ({
getProfile: builder.query<User, void>({
query: () => 'profile',
}),
}),
});

Стили и тема

Хранение темы в app/theme/:

export const theme = {
colors: {
primary: '#4A90E2',
background: '#fff',
text: '#222',
},
spacing: {
sm: 8,
md: 16,
lg: 24,
},
};
  • Использование StyleSheet.create() или tailwind-rn

  • Оборачивать приложение в ThemeProvider (через Context или библиотеку вроде styled-components)

  • Хранить глобальные переменные и стили отдельно от компонентов

UI-компоненты

Все переиспользуемые компоненты, не привязанные к бизнес-логике, выносятся в shared/ui/:

<Button onPress={handleSubmit} title="Сохранить" variant="primary" />
<Avatar source={{ uri: user.avatar }} size="lg" />
<Modal visible={isOpen} onClose={closeModal}>...</Modal>
  • Использование prop-driven архитектуры

  • Универсальность: все стили настраиваются через props

Переиспользуемые блоки

  • shared/components/ — часто используемые секции (Header, Loader, ErrorBoundary)

  • shared/utils/ — форматирование дат, строки, работа с массивами

  • shared/hooks/ — кастомные хуки (useDebounce, usePagination, useKeyboard)

Работа с авторизацией

  • Авторизация через authSlice или authContext

  • Сохранение токенов в AsyncStorage/SecureStore

  • Защищённые маршруты: PrivateRoute, AuthGuard

{isAuthenticated ? <MainStack /> : <AuthStack />}

  • Обновление токена (refresh) через интерсепторы или middleware

Тестирование

  • Jest для юнит-тестов

  • @testing-library/react-native для компонентов

  • Detox для E2E

Организация по уровням:

/\__tests__
/unit
/integration
/e2e

Поддержка CI (GitHub Actions, Bitrise) для прогонки тестов.

Работа с хранилищем и оффлайн-режимом

  • Кэширование данных через react-query, redux-persist, AsyncStorage

  • Работа в оффлайне: сохранение в SQLite, WatermelonDB, realm

  • Синхронизация при восстановлении соединения

Push-уведомления и Background задачи

  • Firebase Cloud Messaging (FCM)

  • OneSignal

  • Обработка через react-native-push-notification или expo-notifications

  • Background Sync через react-native-background-fetch, expo-task-manager

Монорепозитории и модульность

Для крупных команд может использоваться:

  • Monorepo (Turborepo, Nx)

  • Разделение на пакеты: @app/ui, @app/core, @app/utils

Модули могут быть изолированы и использоваться повторно в других проектах.

Безопасность

  • Использование react-native-keychain или expo-secure-store

  • Защита маршрутов

  • Защита критичных экранов (например, повторная авторизация)

  • Проверка версий, device check, root detection

DevOps и окружения

  • Разделение окружений: .env.development, .env.production

  • Использование react-native-config или expo-constants

  • CI/CD: автоматическая сборка и деплой через GitHub Actions, AppCenter, Bitrise

Логгирование и мониторинг

  • Интеграция Sentry или Bugsnag

  • Пользовательская аналитика: Firebase Analytics, Mixpanel

  • Crashlytics для логирования падений

  • Встроенные логгеры logger.ts с уровнями: info, warn, error

Выстраивание архитектуры — это не только структура файлов, но и культура кодирования, согласованные подходы к бизнес-логике, изоляция зависимостей, тестируемость, переиспользуемость и гибкость масштабирования. Успешный масштаб проекта достигается при чётком разделении ответственности и согласованной командной работе.