Материальный дизайн, навигация, сохраняющееся состояние

После настройки среды в Части 1 и создания очень простого первого приложения во Части 2 я был готов к чему-то более амбициозному.

Для моего второго проекта с React Native я хотел сделать что-то, что заставило бы меня исследовать больше API и библиотек. В то же время что-то не слишком сложное, так как я не хотел потеряться в большом проекте, который никогда не закончу.

В конце концов я решил использовать приложение "Библиотека фильмов", где можно искать фильмы, читать их детали, например сюжет, и добавлять их в свою библиотеку фильмов.

Очевидно, мне нужно было вдохновение, поэтому я отправился в Google Play Store и в конце концов нашел идеальное приложение, которое искал. Мне понравился материальный дизайн и функциональность, поэтому я хотел посмотреть, смогу ли я воспроизвести хотя бы его основные концепции.

Для получения данных о фильмах я использовал OMDb API. Это открытый API, который можно использовать бесплатно, большинство метаданных фильмов также включают изображение постера. Однако он немного ограничен в плане поиска, вы можете искать только по названию.

Вы можете найти завершенный проект на GitHub: react-native-app-movies



Давайте посмотрим, какие основные проблемы мне пришлось преодолевать многими невежественными способами (AKA Google Search + Stack Overflow + GitHub).

Материальный дизайн

Главное реализовать был материальный дизайн, поэтому я искал существующие библиотеки на GitHub.

Было несколько доступных с большим количеством звезд:

Мне react-native-material-ui показалась самой простой и активно поддерживаемой библиотекой, поэтому в конце концов я остановился на ней.



Конечно, документация довольно простая, и мне пришлось несколько раз просматривать исходный код, чтобы понять, как все реализовано, но это также случалось и с другими реактивными библиотеками 😃

При этом код выглядит очень хорошо структурированным и хорошо написанным, поэтому его изучение не было рутиной.

Навигация

Сначала я хотел использовать react-native-navigation, но потом обнаружил, что он на самом деле не поддерживается Expo, который вместо этого использует react-navigation.

Кроме того, react-native-navigation требует взаимодействия с нативными модулями и, похоже, требует более высокой кривой обучения.

В конце концов, мне очень понравилась реактивная навигация! На данный момент для меня это просто необходимо.



Чего я не знал, так это того, что он также может делать такие вещи, как добавление навигационного ящика, что мне и было нужно. Этого можно добиться с помощью createDrawerNavigator.

Однако я хотел использовать компонент Ящик, предоставленный react-native-material-ui. К счастью, реактивная навигация позволяет создавать пользовательские компоненты Drawer:

ПРИМЕЧАНИЕ: для фона заголовка ящика я использовал одно из изображений стен из материалов, размещенных на странице https://plus.google.com/+BrianParkerson/posts/QGcBs3E9D4B.

Сначала я просто использовал навигатор ящиков, но потом заметил, что при выполнении this.props.navigation.goBack() для возврата к предыдущему маршруту он всегда возвращался к домашнему маршруту.

Несколько поисков переполнения стека позже я узнал, что мне также нужно использовать createStackNavigator, комбинируя его с навигатором ящиков.

Это можно сделать с помощью кода, такого как следующий

Обратите внимание, что навигатор стека автоматически добавляет заголовок в верхнюю часть экрана, что мне не нужно, так как я уже использовал компонент Панель инструментов из react-native-material-ui.

Таким образом, мне пришлось использовать header: null, чтобы скрыть это.

Вкладки

Мне нужно было реализовать вкладки «Мой список/Избранное», но в используемой мной библиотеке материалов не было компонента Tab, поэтому мне понадобилась другая библиотека.

В конце концов я нашел react-native-tab-view, который очень хорошо работает из коробки.



Он также имеет встроенные анимации, такие как изменение текущей вкладки с помощью жестов смахивания!

Подгонка изображений

API OMDb возвращает изображения постеров переменного размера. Мне нужен был способ полностью отобразить эти изображения, не зная заранее их размера.

Сначала я пытался использовать обычный компонент Изображение и авто/процентную ширину, но они не работали. Изображения расширялись только до существующей высоты контейнера, вместо того, чтобы расширять контейнер, чтобы соответствовать им.

Мне еще предстоит многому научиться в этой области, возможно, я что-то упускаю, я также просмотрел некоторые проблемы с реакцией на GitHub, которые в значительной степени предполагают использование внешних библиотек.

В итоге я предложил использовать библиотеку react-native-fit-image.



Он работает и выполняет свою работу, у него также есть встроенные индикаторы загрузки, однако разработка библиотеки кажется устаревшей (последний коммит был сделан в ноябре 2017 года).

Упущены важные вещи, такие как обработка ошибок (насколько я видел). Для следующего проекта я мог бы рассмотреть какую-то альтернативу.

Сохраняющееся состояние

Это функция, необходимая для предотвращения исчезновения сохраненных фильмов при перезагрузке приложения.

Для этого есть несколько вариантов, но, поскольку приложение использует избыточность, кажется, что самым простым способом является использование redux-persist со значением по умолчанию AsyncStorage, предоставляемым react -родной.



В текущих версиях Android существует ограничение в 6 МБ памяти, этого более чем достаточно для моего варианта использования, но, возможно, мне придется поискать что-то более надежное для будущих приложений.

Взгляните на store.js для моей реализации.

Бонус: стереть все

Наконец, я хотел реализовать функцию «стереть все данные», чтобы полностью очистить как постоянные, так и локальные данные.

Я знал, что для очистки сохраненных данных достаточно вызвать persistor.purge()
А как насчет локального состояния? По сути, мне нужен был способ сбросить состояние приведения к любому начальному состоянию, которое я определил в своих редукторах.

Обычный быстрый поиск в Google привел к этому отличному ответу Дэна Абрамова, (со-)создателя Redux.

По сути, вы можете обернуть свои комбинированные редукторы в корневой редуктор, который при получении действия, такого как ROOT_RESET,, возвращает состояние в неопределенное.

Таким образом, каждый комбинированный редьюсер будет возвращать исходное состояние.

Идти дальше

Что осталось? Разработка все больше и больше приложений наверняка!

Я также хочу посмотреть на фазу публикации, т.е. фактическое попадание в магазин приложений. Для этого мне нужно придумать что-нибудь приличное. Это может быть настоящим испытанием 😃

Обязательно ждите следующих статей, чтобы узнать, что пошло не так, и как мне удалось решить проблемы более простыми способами!