
React Native + Expo: быстрая разработка
Expo — это слой инструментов и сервисов вокруг React Native, который позволяет стартовать и двигаться значительно быстрее: меньше нативной настройки, больше готовых модулей, стабильная среда разработки и облачные сборки. В этой статье — практический, «быстрый» маршрут: от создания проекта до публикации сборок, с фокусом на типичных задачах MVP.
1. Почему Expo ускоряет
- Быстрый старт без нативной конфигурации (iOS/Android не нужны для первого запуска).
- Готовые модули: камера, уведомления, безопасное хранилище, обновления «по воздуху» и многое другое.
- Облачные сборки через EAS Build — без локальной установки Xcode/Android SDK.
- Консистентная DX: Expo Dev Tools, логирование, туннели, профилирование.
- Возможность «сойти» на Bare Workflow, если понадобится полный натив.
Практическое правило: начните с Expo. Если позже потребуется глубокая нативная интеграция — мигрируйте на Bare.
2. Создание проекта
npm create expo@latest myapp
cd myapp
npm run start
Откройте Expo Dev Tools в браузере. Запустите приложение в Expo Go на устройстве (QR‑код) или в эмуляторе Android/симуляторе iOS.
3. Expo Router: быстрее, чем вручную настраивать навигацию
Expo Router использует файловую систему для маршрутов — минимум кода, максимум скорости.
npm i expo-router react-native-safe-area-context react-native-screens
Затем включите Router в app/_layout.tsx
:
// app/_layout.tsx
import { Stack } from 'expo-router';
import { SafeAreaProvider } from 'react-native-safe-area-context';
export default function RootLayout() {
return (
<SafeAreaProvider>
<Stack>
<Stack.Screen name="index" options={{ title: 'Главная' }} />
<Stack.Screen name="details" options={{ title: 'Детали' }} />
</Stack>
</SafeAreaProvider>
);
}
Создайте страницы app/index.tsx
и app/details.tsx
:
// app/index.tsx
import { Link } from 'expo-router';
import { View, Text, StyleSheet } from 'react-native';
export default function Index() {
return (
<View style={styles.container}>
<Text style={styles.title}>Expo: быстрый старт</Text>
<Link href="/details?id=42">Перейти к деталям</Link>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, padding: 16, justifyContent: 'center' },
title: { fontSize: 20, fontWeight: '600', marginBottom: 8 }
});
// app/details.tsx
import { useLocalSearchParams } from 'expo-router';
import { View, Text } from 'react-native';
export default function Details() {
const { id } = useLocalSearchParams<{ id?: string }>();
return (
<View style={{ flex: 1, padding: 16 }}>
<Text>Детали элемента: {id}</Text>
</View>
);
}
Преимущества:
- Маршруты соответствуют файлам в
app/
. - Готовая поддержка стеков, табов, модалок.
- Глубокие ссылки и параметры из коробки.
4. UI и стили: базовый экран
// components/Hello.tsx
import { View, Text, StyleSheet } from 'react-native';
export function Hello({ name }: { name: string }) {
return (
<View style={styles.container}>
<Text style={styles.title}>Привет, {name}!</Text>
<Text>Expo + RN позволяют очень быстро собрать MVP.</Text>
</View>
);
}
const styles = StyleSheet.create({
container: { padding: 16 },
title: { fontSize: 18, fontWeight: '600', marginBottom: 8 }
});
Используйте компонент на странице:
// app/index.tsx (фрагмент)
import { Hello } from '../components/Hello';
// ...
<Hello name="мир" />
5. Работа со списком и API
// app/posts.tsx
import { useEffect, useState } from 'react';
import { View, Text, FlatList, ActivityIndicator, TouchableOpacity } from 'react-native';
type Post = { id: number; title: string };
export default function Posts() {
const [data, setData] = useState<Post[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
(async () => {
try {
const res = await fetch('https://jsonplaceholder.typicode.com/posts?_limit=20');
const json = (await res.json()) as Post[];
setData(json);
} finally {
setLoading(false);
}
})();
}, []);
if (loading) return <ActivityIndicator style={{ marginTop: 24 }} />;
return (
<FlatList
data={data}
keyExtractor={item => String(item.id)}
renderItem={({ item }) => (
<TouchableOpacity style={{ padding: 12 }}>
<Text style={{ fontWeight: '600' }}>{item.title}</Text>
</TouchableOpacity>
)}
ItemSeparatorComponent={() => <View style={{ height: 1, backgroundColor: '#eee' }} />}
contentContainerStyle={{ padding: 12 }}
/>
);
}
Советы:
- Для реальных API добавьте обработку ошибок, кэш и «pull‑to‑refresh».
- Для серверного состояния рассмотрите TanStack Query или RTK Query.
6. Популярные модули Expo
- Безопасное хранилище:
expo-secure-store
— храните токены безопасно. - Камера/медиа:
expo-camera
,expo-image-picker
. - Уведомления:
expo-notifications
. - Обновления «по воздуху»:
expo-updates
. - Биометрия:
expo-local-authentication
.
Пример безопасного хранилища:
npm i expo-secure-store
// lib/secure.ts
import * as SecureStore from 'expo-secure-store';
export async function saveToken(token: string) {
await SecureStore.setItemAsync('auth:token', token);
}
export async function loadToken() {
return SecureStore.getItemAsync('auth:token');
}
7. Типизация с TypeScript
npm i -D typescript @types/react @types/react-native
Добавьте tsconfig.json
и используйте .ts
/.tsx
. Типизируйте параметры роутера (useLocalSearchParams<...>()
), пропсы компонентов и ответы API — это снижает число скрытых ошибок.
8. Производительность и размер бандла
- Избегайте лишних ре‑рендеров: мемоизация компонентов/селекторов, вынос коллбэков.
- Используйте
FlatList
/SectionList
для больших списков. - Отложенная загрузка экранов (файловая маршрутизация делает это естественным).
- Следите за размером ассетов: оптимизируйте изображения, используйте
.webp
.
9. Сборка и публикация через EAS
npm i -g eas-cli
npx expo login
npx eas build:configure
# Android
npx eas build -p android --profile preview
# iOS
npx eas build -p ios --profile preview
- Профили сборки настраиваются в
eas.json
. - Ссылки на сборки доступны в кабинете Expo — удобно для QA/стейкхолдеров.
OTA‑обновления (без публикации в сторах):
npx expo publish
Учитывайте правила магазинов: OTA предназначены для JS‑изменений, не для добавления новых нативных модулей.
10. Когда Bare Workflow
- Нужны кастомные нативные SDK/модули, отсутствующие в Expo.
- Гранулярная настройка Gradle/Xcode, специфические плагины.
- Необходимо подключить библиотеки, несовместимые с Managed Workflow.
Миграция выполнима в любой момент, но планируйте её под релизное окно.
11. Частые ошибки и как их избежать
- Слишком ранний уход с Expo: потеряете скорость. Начните с Managed и измерьте, чего реально не хватает.
- Хранение секретов в AsyncStorage: используйте
expo-secure-store
. - Отсутствие стратегий кэша/ошибок для API: внедрите TanStack Query/RTK Query.
- Игнорирование производительности списков: без
FlatList
UI начнёт «задыхаться».
Итоги
Expo + React Native — самый быстрый путь к работающему мобильному приложению: файловая маршрутизация через Expo Router, набор готовых модулей, облачные сборки EAS и OTA‑обновления. Начните с Managed Workflow, добавьте типизацию и базовую архитектуру, а при росте требований переходите на Bare.