# Как создать приложение для медитации на Expo Router: полный гайд от freeCodeCamp.org

Источник: https://www.youtube.com/watch?v=9UKCv9T_rIo
Канал: freeCodeCamp.org
Опубликовано: 02.07.2024

---

В новом обучающем курсе от платформы freeCodeCamp.org разработчик Стивен Гарсия (Steven Garcia) детально разбирает процесс создания мобильного приложения для медитации. Проект строится на стеке React Native и Expo Router с использованием TypeScript и NativeWind для стилизации, предлагая разработчикам среднего уровня освоить современные подходы к кроссплатформенной разработке [0:00].

## 🛠 Подготовка окружения и запуск проекта
[[JUMP:03:41]]

Перед началом работы Стивен Гарсия подчеркивает, что данный курс не предназначен для абсолютных новичков и предполагает знание основ веб-разработки: JavaScript, React и Tailwind CSS [02:44]. Для локальной разработки автор рекомендует использовать симуляторы: Xcode для iOS (только на macOS) и Android Studio для Android [04:05].

Основные шаги по настройке среды:

*   **Xcode:** Установка через App Store, проверка наличия Command Line Tools в настройках (Locations) [04:20].
*   **Android Studio:** Установка SDK (версия Android 14 на момент записи), компонентов Android Emulator и SDK Platform-Tools [05:19].
*   **VS Code:** Установка расширений Prettier, ES7+ React/Redux/React Native snippets, Expo Tools и Tailwind CSS IntelliSense [07:39].

Инициализация проекта выполняется командой `npx create-expo-app@latest`. Автор называет проект `simple-meditation` [08:43]. После установки зависимостей проект запускается через `npx expo start --clear`, что генерирует QR-код для тестирования в приложении Expo Go или позволяет запустить симулятор нажатием клавиш `i` (iOS) или `a` (Android) [10:01].

## 📂 Архитектура и файловый роутинг в Expo Router
[[JUMP:11:41]]

Expo Router привносит в мобильную разработку привычную по Next.js концепцию файлового роутинга. По мнению Стивена Гарсии, это значительно упрощает навигацию в приложении [14:24].

Структура проекта после очистки от бойлерплейта:

1.  **Директория `app`**: Содержит основные экраны и файлы макетов (`_layout.tsx`).
2.  **Директория `assets`**: Шрифты, изображения и аудиофайлы (доступны по ссылке в описании видео) [15:05].
3.  **Директория `components`**: Переиспользуемые элементы интерфейса.
4.  **Директория `constants`**: Статические данные (списки медитаций, пути к изображениям) [15:31].

Гарсия объясняет работу файла `_layout.tsx`, который определяет общую структуру интерфейса для всех вложенных файлов в папке. Использование компонента `Slot` из `expo-router` позволяет рендерить дочерние маршруты внутри макета, подобно `children` в веб-приложениях [23:52].

## 🎨 Стилизация с помощью NativeWind и создание главной страницы
[[JUMP:18:38]]

Для верстки приложения используется NativeWind — адаптация Tailwind CSS для React Native. Процесс установки включает:

*   Установку пакетов `nativewind` и `tailwindcss` [19:03].
*   Инициализацию конфигурации командой `npx tailwindcss init` [19:16].
*   Настройку `tailwind.config.js` с указанием путей к файлам компонентов и настройкой кастомных шрифтов [19:42].
*   Добавление плагина `nativewind/babel` в файл `babel.config.js` [19:56].

Главная страница приложения создается на базе компонента `ImageBackground` с использованием эффекта линейного градиента. Для этого устанавливается библиотека `expo-linear-gradient` [24:19]. Стивен демонстрирует создание переиспользуемого компонента `CustomButton.tsx`, который принимает пропсы `onPress`, `title`, а также кастомные стили для контейнера и текста [28:36].

## 🧘 Реализация списка медитаций и вкладочной навигации
[[JUMP:34:31]]

Для организации навигации в нижней части экрана (tabs) создается директория `(tabs)`. Круглые скобки в названии папки в Expo Router означают создание группы маршрутов, которая не отображается в URL пути [34:45].

Основные этапы разработки экрана «Nature Meditate»:

*   **FlatList**: Используется для отображения вертикального списка доступных медитаций. Автор подчеркивает важность использования `keyExtractor` для уникальной идентификации элементов [43:15].
*   **Иконки**: Для таб-бара используются иконки из библиотеки `@expo/vector-icons` (например, `MaterialCommunityIcons`) [53:46].
*   **Динамические маршруты**: Создание страницы отдельной медитации через файл `[id].tsx`. Гарсия объясняет, как извлекать параметры маршрута с помощью хука `useLocalSearchParams` [1:21:13].

Стивен акцентирует внимание на создании компонента `AppGradient.tsx`, который оборачивает контент в линейный градиент и `SafeAreaView`, предотвращая перекрытие элементов системными индикаторами (заряд батареи, время) [37:24].

## 🔋 Логика таймера и воспроизведение аудио
[[JUMP:1:24:43]]

Сердце приложения — экран медитации с обратным отсчетом. Логика строится на хуках `useState` и `useEffect`.

*   **Таймер**: Переменная `secondsRemaining` инициализируется значением по умолчанию (например, 10 секунд). В `useEffect` используется `setTimeout`, который уменьшает значение на 1 каждую секунду [1:26:11].
*   **Очистка**: Крайне важно очищать таймер через `clearTimeout(timerId)` при размонтировании компонента, чтобы избежать утечек памяти [1:26:51].
*   **Аудио**: Для работы со звуком устанавливается библиотека `expo-av` [1:35:09]. Функция `initializeSound` загружает аудиофайл, соответствующий выбранной медитации, а `unloadAsync` останавливает воспроизведение при выходе с экрана [1:40:01].

Для корректного отображения времени Стивен реализует функцию форматирования, которая добавляет ведущие нули (padding), используя методы `math.floor` и `padStart(2, "0")` [1:32:11].

## 📝 Аффирмации и глобальное состояние через Context API
[[JUMP:56:06]]

Раздел аффирмаций организован как горизонтальная галерея категорий. Каждая категория ведет на отдельный экран, где текст аффирмации разбивается на предложения по точкам и выводится в виде списка [1:12:42].

Для управления длительностью медитации на разных экранах автор внедряет **React Context API** [1:48:12]:

1.  Создается `TimerContext` для хранения значения `duration` и функции `setDuration`.
2.  Компонент `TimerProvider` оборачивает всё приложение в `_layout.tsx`, делая состояние доступным в любом дочернем компоненте [1:50:52].
3.  Это позволяет пользователю выбрать длительность в модальном окне (`Modal`), и это изменение мгновенно отразится на главном экране таймера без «прокидывания» пропсов (prop drilling) [1:53:10].

В завершение курса Стивен Гарсия отмечает, что созданное приложение — это отличная база для портфолио, демонстрирующая владение современными инструментами экосистемы Expo [1:55:00].