Лекция 3. Введение в Expo и React Native
Введение
Разработка мобильных приложений традиционно делится на два направления:
- Нативная разработка — отдельный код под каждую платформу (Swift/Objective-C для iOS, Kotlin/Java для Android).
- Кроссплатформенная разработка — единый код, который работает на обеих платформах.
Кроссплатформенный подход экономит время и силы команды: вместо двух кодовых баз поддерживается одна. Одним из самых популярных инструментов этого направления является React Native, а на его основе построена платформа Expo, которая упрощает разработку, тестирование и публикацию приложений.
Цель лекции — разобраться, что такое React Native и Expo, из чего состоит экосистема Expo, как устроен типичный проект и как выглядит минимальное работающее приложение.
Практическая установка окружения и первый запуск проекта на вашем компьютере вынесены в практику 3 (
practice_03.md). Здесь мы рассматриваем теорию и устройство проекта.
1. Что такое React Native
React Native (RN) — это фреймворк от компании Meta для создания мобильных приложений на JavaScript. Он опирается на библиотеку React, которая изначально создавалась для веба.
Ключевые идеи:
- Один язык — JavaScript (или TypeScript). Логика приложения пишется на JS.
- JSX — расширение синтаксиса JavaScript, позволяющее описывать интерфейс в виде «разметки» прямо в коде.
- Компонентный подход. Интерфейс собирается из переиспользуемых компонентов (как кубики).
- Настоящие нативные виджеты. В отличие от гибридных решений (WebView), RN не рисует интерфейс в браузере — он создаёт настоящие нативные элементы платформы.
1.1. Как RN превращает JS-компоненты в нативные виджеты
Это важный момент для понимания. Когда вы пишете <Text> или <View>, на экране появляются не HTML-теги, а реальные нативные элементы: на iOS это UIView/UILabel, на Android — android.view.View/TextView.
Связь между миром JavaScript и миром нативного кода обеспечивает специальный слой:
- Bridge (мост) — классический механизм. JS-код и нативный код работают в разных потоках и обмениваются сообщениями в виде сериализованного JSON. Команда «создай кнопку» проходит через мост и превращается в нативный виджет.
- JSI (JavaScript Interface) — новая архитектура RN. Она заменяет асинхронный мост на прямой синхронный вызов: JavaScript может напрямую обращаться к нативным объектам без сериализации. Это быстрее и снимает «узкое место» старого моста.
[ Ваш JS/JSX код ] │[ React (виртуальное дерево компонентов) ] │[ Bridge / JSI ] ← слой связи JS ↔ Native │[ Нативные виджеты iOS / Android ]Для нас на этом курсе достаточно понимать: вы пишете на JavaScript, а пользователь видит настоящий нативный интерфейс.
2. Что такое Expo
Expo — это платформа и набор инструментов поверх React Native. Если RN — это «двигатель», то Expo — это «удобная машина вокруг него»: готовая сборка, набор инструментов и библиотек.
Главная ценность Expo — быстрый старт: можно начать разработку без установки Xcode и Android Studio и сразу запустить приложение на своём телефоне.
2.1. Экосистема Expo
Экосистема состоит из нескольких частей:
- Expo CLI — инструмент командной строки для создания, запуска и управления проектом (
create-expo-app,expo start). - Expo Go — мобильное приложение для iOS и Android. Позволяет запускать ваш проект на реальном устройстве без компиляции — достаточно отсканировать QR-код.
- Expo SDK — большой набор готовых модулей для работы с устройством: камера (
expo-camera), геолокация (expo-location), уведомления (expo-notifications), сенсоры (expo-sensors) и многое другое. - EAS (Expo Application Services) — облачные сервисы для сборки готовых приложений (EAS Build), отправки в App Store / Google Play (EAS Submit) и обновлений (EAS Update).
- OTA-обновления (Over-The-Air) — возможность доставлять обновления JavaScript-части приложения пользователям без повторной публикации в магазинах.
2.2. Преимущества Expo
- быстрый старт без нативных IDE (Xcode/Android Studio);
- единый код для iOS и Android;
- большой набор готовых модулей в Expo SDK;
- удобное тестирование на устройстве через Expo Go;
- облачные сборки и OTA-обновления;
- большое сообщество и документация.
2.3. Ограничения Expo
- не все нативные библиотеки совместимы из коробки — иногда нужны development builds или переход на «bare» workflow;
- размер приложения может быть больше, чем у «чистого» нативного;
- зависимость от экосистемы и версий Expo SDK;
- для очень специфичных нативных задач может потребоваться писать нативный код.
На практике для большинства учебных и многих коммерческих проектов возможностей Expo более чем достаточно.
3. Структура типичного Expo-проекта
После создания проекта командой npx create-expo-app появляется набор файлов и папок. Рассмотрим ключевые из них.
my-app/├── app/ // экраны при использовании expo-router (file-based routing)│ ├── _layout.tsx // корневой layout (обёртка навигации)│ └── index.tsx // главный экран ("/")├── assets/ // картинки, шрифты, иконки├── components/ // переиспользуемые компоненты (опционально)├── node_modules/ // установленные зависимости (не редактируется вручную)├── App.js // точка входа в "классическом" шаблоне├── app.json // конфигурация приложения (имя, иконка, версия...)├── babel.config.js // настройка транспайлера Babel├── package.json // зависимости и скрипты проекта└── tsconfig.json // настройки TypeScript (если используется TS)3.1. Ключевые файлы
package.json — «паспорт» проекта. Содержит список зависимостей и скрипты запуска:
{ "name": "my-app", "version": "1.0.0", "main": "expo-router/entry", "scripts": { "start": "expo start", "android": "expo start --android", "ios": "expo start --ios" }, "dependencies": { "expo": "~51.0.0", "react": "18.2.0", "react-native": "0.74.0" }}Поле main указывает точку входа приложения. В классическом шаблоне это App.js, а при использовании expo-router — специальный модуль expo-router/entry.
app.json (или app.config.js) — конфигурация самого приложения: имя, slug, версия, иконка, splash-экран, ориентация экрана, настройки платформ.
{ "expo": { "name": "My App", "slug": "my-app", "version": "1.0.0", "orientation": "portrait", "icon": "./assets/icon.png", "splash": { "image": "./assets/splash.png", "backgroundColor": "#ffffff" } }}Вариант app.config.js нужен, когда конфигурацию надо строить динамически (например, читать значения из переменных окружения).
App.js / app/_layout — главный компонент приложения.
- В классическом шаблоне корневой компонент описывается в
App.js. - В шаблоне с expo-router используется папка
app/, где каждый файл — это экран, а_layoutзадаёт общую обёртку (навигацию). Маршруты строятся по структуре файлов (file-based routing), как в Next.js.
assets/ — статические ресурсы: изображения, иконки, шрифты. На них ссылаются из app.json и из кода.
babel.config.js — настройка Babel, инструмента, который преобразует современный JS/JSX в код, понятный движку. Для Expo обычно содержит пресет babel-preset-expo:
module.exports = function (api) { api.cache(true); return { presets: ['babel-preset-expo'], };};node_modules/ — папка с установленными библиотеками. Её не редактируют руками и не добавляют в систему контроля версий.
4. Запуск проекта (кратко)
Полный разбор установки и запуска — в практике 3. Здесь — общая последовательность, чтобы видеть картину целиком.
- Создание проекта:
npx create-expo-app my-appcd my-app- Запуск сервера разработки:
npx expo startПосле запуска в терминале появляется QR-код и адрес локального сервера (Metro bundler).
- Открытие на устройстве:
- установите приложение Expo Go на телефон;
- отсканируйте QR-код камерой (iOS) или внутри Expo Go (Android);
- приложение откроется и будет обновляться вживую при изменении кода (Fast Refresh).
Альтернативно можно запустить на эмуляторе Android или симуляторе iOS клавишами a / i в терминале.
5. Разбор простого приложения
Рассмотрим минимальное работающее приложение — счётчик. Это пример классического шаблона с корневым компонентом App.
// App.js — точка входа приложенияimport { useState } from 'react';import { Text, View, Button, StyleSheet } from 'react-native';
// Корневой компонент. export default делает его точкой входа.export default function App() { // useState создаёт состояние count с начальным значением 0 const [count, setCount] = useState(0);
// Компонент возвращает дерево JSX, которое будет отрендерено return ( <View style={styles.container}> <Text style={styles.title}>Привет, Expo!</Text> <Text>Счётчик: {count}</Text> <Button title="Увеличить" onPress={() => setCount(count + 1)} /> </View> );}
const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', }, title: { fontSize: 20, fontWeight: 'bold', },});5.1. Что здесь происходит
- Точка входа. Expo загружает модуль, указанный в
package.json(main). В классическом шаблоне этоApp.js, который экспортирует по умолчанию (export default) корневой компонентApp. - Корневой компонент. Функция
App— это функциональный компонент. Она возвращает JSX — описание интерфейса. - Рендер. RN берёт это описание, строит виртуальное дерево компонентов и превращает его в нативные виджеты на экране.
View— базовый контейнер (аналогdivв вебе), организует расположение элементов.Text— элемент для отображения текста. В RN любой текст должен находиться внутри<Text>.Button— кнопка с обработчиком событияonPress.useState— хук, который хранит состояние. При вызовеsetCountкомпонент перерисовывается с новым значением.StyleSheet— способ описывать стили. Используется Flexbox и свойства, похожие на CSS (flex,justifyContent,alignItems,fontSize).
5.2. То же приложение в стиле expo-router
Если проект создан с expo-router, главный экран лежит в app/index.js, а корневая обёртка — в app/_layout.js:
// app/_layout.js — корневой layout, описывает навигациюimport { Stack } from 'expo-router';
export default function Layout() { return <Stack />;}// app/index.js — главный экран по маршруту "/"import { useState } from 'react';import { Text, View, Button } from 'react-native';
export default function Home() { const [count, setCount] = useState(0); return ( <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> <Text>Счётчик: {count}</Text> <Button title="Увеличить" onPress={() => setCount(count + 1)} /> </View> );}Разница только в организации файлов: при file-based routing каждый файл в app/ автоматически становится экраном, а точкой входа служит expo-router/entry.
Краткие итоги
- React Native — фреймворк для создания мобильных приложений на JavaScript; интерфейс собирается из компонентов и превращается в настоящие нативные виджеты iOS/Android.
- Связь между JS и нативным кодом обеспечивает мост (bridge), а в новой архитектуре — JSI (прямой синхронный доступ без сериализации).
- Expo — платформа поверх RN для быстрого старта. Экосистема: CLI, Expo Go, Expo SDK, EAS, OTA-обновления.
- Плюсы Expo — быстрый старт, единый код, готовые модули; минусы — ограничения с некоторыми нативными библиотеками и зависимость от экосистемы.
- Ключевые файлы проекта:
package.json(зависимости и точка входа),app.json/app.config(конфигурация),App.jsилиapp/_layout(корневой компонент),assets/,babel.config.js. - Запуск:
create-expo-app→expo start→ Expo Go по QR-коду (подробности в практике 3). - Минимальное приложение состоит из точки входа, корневого компонента и возвращаемого им JSX, который рендерится в нативный интерфейс.
Вопросы для самопроверки
- Что такое React Native и как он связан с библиотекой React? Чем нативные виджеты отличаются от гибридного (WebView) подхода?
- Для чего нужен мост (bridge) в React Native и в чём преимущество архитектуры JSI?
- Из каких частей состоит экосистема Expo (CLI, Expo Go, SDK, EAS, OTA) и какие задачи решает каждая из них? Назовите ключевые файлы проекта Expo и их назначение.