[Перевод] Записки фрилансера: разработка первого React Native-приложения

Автор материала, перевод которого мы публикуем, недавно выпустил своё первое мобильное приложение, написанное на React Native. Так случилось, что это приложение стало и его первым проектом, который он создал как программист-фрилансер. Здесь он расскажет о том, с чем ему пришлось столкнуться в ходе работы — от инициализации проекта до его публикации в App Store и Google Play.

y80ncfpjzzebavsfo8s2ehrotss.jpeg

Почему я выбрал фриланс?


В мае прошлого года мне подвернулся один замечательный фриланс-проект. В то время я был фуллстек-разработчиком в одном стартапе в Стокгольме. Это была моя первая программистская работа, я устроился туда всего лишь год назад (тут я рассказываю об этом подробнее).

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

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

Тут вы можете задаться вопросом о том, почему некто вообще может пытаться заняться мобильной разработкой после того, как и года не проработал в роли профессионального веб-разработчика? Не разумней было бы продолжать набираться опыта в избранной нише, профессионально расти, формировать впечатляющее резюме?

Я полностью согласен с тем, что это было бы куда разумней. Но я — безнадёжный «многостаночник», который несколько лет тому назад решил принимать карьерные решения, основываясь не на некоей стратегии, а на своих собственных предпочтениях. Я решил заниматься тем, что приносит мне радость. Другими словами, моё резюме уже сейчас выглядит таким, что его вряд ли можно привести в ещё более беспорядочное состояние.

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

Что сделало этот проект таким притягательным для меня? Что сделало его интереснее работы над стремительно развивающимся продуктом, которым пользуются тысячи компаний, в составе команды, состоящий из лучших людей, которых мне довелось встречать? На этот вопрос можно ответить так: это свобода, это вызов, который бросила мне необходимость решить сложную задачу, и это стремление к саморазвитию.

Почему было решено использовать React Native?


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

Одно из агентств прислало наброски дизайна приложения, которые, кроме того, что неопрятно выглядели, ещё и не соответствовали фирменному стилю, отражённому на сайте клиента. Ещё одно предложило заоблачные цены — и на разработку, и на поддержку проекта. Третье же, похоже, отправило предложение, даже не изучив толком требований клиента. У всех агентств, приславших предложения, была общая черта: они собирались создавать приложение с использованием гибридного фреймворка Cordova.

Но и это ещё не всё. Хотя Cordova — инструмент совершенно бесплатный и опенсорсный, одно из агентств даже попыталось скрыть сведения о том, какую конкретно технологию оно использует. Вместо этого представители агентства говорили о «собственной» платформе для разработки мобильных приложений, созданной внутри компании. Такое ощущение, что речь шла о небольшой надстройке над Cordova, сделанной только для того, чтобы прочно закрепить за этим агентством эксклюзивные права на обслуживание приложения и сделать возможный будущий переход заказчика к другому разработчику сложным и дорогим. В целом, предложения, о которых идёт речь, оказались не особо впечатляющими.

Надо отметить, что я ничего не имею против гибридных фреймворков. Я постоянно пользуюсь приложениями, которые построены на их основе. Это, например, Gmail, Slack, Atom, Figma. Однако тогда я уже некоторое время слышал о React Native, о том, как эта библиотека позволяет создавать кросс-платформенные мобильные приложения с использованием JavaScript, которые не были гибридными!

И что теперь? Нужно ли, каким-то хитрым способом, поддерживать iOS и Android при разработке нативных приложений на JavaScript? Такой вопрос возник у меня из-за того, что когда я интересовался подобными приложениями, оказалось, что iOS-приложения пишут с использованием Objective-C или Swift, а для разработки Android-приложений применяют Java или Kotlin.

Конечно, особых хитростей тут нет. Поэтому у меня возник ещё один вопрос. Как можно называть React Native-приложения настоящими нативными приложениями? Если ответить на этот вопрос в двух словах, то оказывается, что всё дело в API. На то, чтобы это понять, у меня ушло больше времени, чем мне хотелось бы признавать, но то, как React Native-приложения, называющиеся нативными, работают с мобильными платформами, заключается не в запуске JavaScript-кода и не в компиляции такого кода в нативный код. Всё дело в том, что эти приложения выполняют запросы к API, которые выводят нативные компоненты средствами Objective-C на iPhone и средствами Java на Android.

Если вы хотите глубже ознакомиться с основами React Native — рекомендую этот ответ на Quora, это выступление с React Conf, и этот материал, в котором рассказывается о выходе React Native.

Хотя тогда я и не знал о том, что именно происходит в недрах React Native-приложений, я знал, что работа таких приложений сводится к выполнению нативного кода. Это стало моим главным аргументом против выбора одного из решений, основанных на Cordova, предлагаемых агентствами. Я считал, что если компании нужно мобильное приложение, то это приложение должно быть нативным. Если же кому-то нужно приложение, построенное на базе HTML/CSS/JS, то деньги лучше будет потратить просто на улучшение мобильных возможностей его веб-приложения.

Когда я поделился этими рассуждениями с клиентом, он задал мне вопрос о том, знаю ли я кого-нибудь, кто может подобное приложение создать. Я ответил, что не знаю. Тогда меня спросили о том, могу ли я сам это сделать. «Не могу», — ответил я. Однако я к тому моменту уже всем этим заинтересовался и просто не мог не поэкспериментировать с React Native, взяв за основу своих экспериментов спецификации приложения.

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

Спецификации приложения


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

Клиент, для которого разрабатывается приложение, это компания в Стокгольме, которая занимается управлением коворкингами, коллективными офисами. Другими словами, речь идёт об офисных пространствах, которые могут арендовать различные компании. В настоящий момент у моего клиента около 10 подобных действующих офисов, в которых арендуют места примерно 400 компаний с 1400 сотрудниками. Эти вот наниматели офисов и являются целевой аудиторией приложения.

6648e2b6b9a65f42334a4c7999c2ce88.jpg


Зона отдыха в одном из коворкингов

После обсуждения будущего приложения с менеджером проекта мне удалось выяснить некоторые требования к проекту:

  • Возможность входа в систему, выхода из неё и сброса пароля. Обратите внимание на то, что все учётные записи пользователей создают администраторы и приложение не поддерживает регистрацию в системе. Поэтому если вы решите это приложение скачать, то поработать с ним у вас не получится.
  • Просмотр и редактирование профиля пользователя: имя, адрес электронной почты, пароль, аватарка.
  • Поддержка push-уведомлений.
  • Раздел Home, с помощью которого пользователь может ознакомиться с новостями компании в целом, и, в частности, с новостями, касающимися коворкинга, арендуемого компанией.
  • Раздел Community, с помощью которого пользователь может просматривать сведения о различных коворкингах, связываться с их менеджерами и видеть, какие компании занимают некий коворкинг.
  • Раздел Conference, с помощью которого можно бронировать переговорные комнаты и управлять бронированием.
  • Раздел Selection, в котором пользователь может найти эксклюзивные скидки и предложения.
  • Сначала нужно создать iOS-версию, потом добавить поддержку Android.
  • Веб-приложение для администратора, которое позволяет управлять сведениями, выводимыми в React Native-приложении. Хотя тут я, в основном, буду говорить о том, что касается фронтенд-разработки, полагаю, уместно будет упомянуть о том, что серверная часть приложения для администратора создана на базе Ruby on Rails, Postgres и Heroku.


Можно заметить, что этот проект отличается довольно-таки скромными требованиями. Пожалуй, именно что-то в этом духе можно назвать хорошим примером первого приложения, которое некто собирается разработать, используя новый для себя набор технологий. Если вам интересно взглянуть на то, что у меня в итоге получилось (и попутно решить — стоит ли тратить время на чтение рассказа о том, как именно всё это у меня получилось) — вот обзор первой версии приложения.

4f28c68b485bf637135e88b184e3e0b5.png


Первая версия приложения

Ещё читаете? Отлично, тогда давайте двигаться дальше.

Учимся у лучших


Представьте, что вы пообещали друзьям построить им дом. Но вы не знаете о том, как это делается. Вы толком не знаете даже о том, с чего начать. Что в такой ситуации нужно сделать в первую очередь? Ответ очевиден: найти того, кто умеет строить дома и у него поучиться.

Собственно говоря, именно это я и попытался сделать. И мне очень повезло найти именно то, что нужно. Так, всего после нескольких часов поисков учебных материалов по React Native, я нашёл на YouTube гарвардский видеокурс по React Native, состоящий из 13 частей. Каждая лекция длительностью 90–120 минут была посвящена отдельной теме. В результате передо мной оказалось примерно 23 часа высококачественных учебных материалов.

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

Теперь я могу говорить о том, что тот курс, без сомнения, это лучшее, что мне удалось найти. Сжатые и отлично подготовленные занятия, конечно, сыграли огромную положительную роль в учёбе, но я не могу не отметить и мастерство преподавателя. Я описал бы стиль ведения этих занятий следующими словами: скорость, крайняя практичность, целенаправленность. Никакой воды, никаких не относящихся к делу шуток или историй из жизни. В отличие от того, что пишет тут ваш покорный слуга…

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

В результате, если вы хотите найти точку опоры для своего первого React Native-приложения, я с уверенностью рекомендую вам этот курс. Хотя тут надо отметить одну особенность. В том курсе используется набор инструментов Expo. Это — отличное средство, которое подойдёт для большинства простых приложений, которое берёт на себя всяческие тонкости, касающиеся работы с мобильными платформами. Но если вы, как и я, хотите создать основу для проекта, который, скорее раньше, чем позже, может превратиться в довольно большое и сложное приложение, и вы, при этом, хотите полной свободы действий, вероятно, вам лучше подойдёт инициализация проекта средствами React Native.

Вторым «учебным ресурсом», которым я мог пользоваться, оказались мои коллеги. По счастливой случайности в компании, где я тогда работал, тоже начали разработку React Native-проекта. Хотя я сам этим проектом и не занимался, я очень многое узнал, просто общаясь с теми, кто над этим проектом работал, и анализируя их код.

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

Окружение разработки


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

Если вы пришли в React Native-среду из обычной веб-разработки, то надо отметить, что многое здесь покажется вам знакомым. Для меня это означало то, что я продолжил использовать, в качестве редактора кода, Atom, в качестве терминала — iTerm, а в качестве интерфейса для работы с git — GitUp. (Если это сейчас читают фанаты Vim — предлагаю каждому остаться при своём мнении.) Но, помимо вышеперечисленных инструментов, для разработки React Native-приложений мне понадобилось кое-что ещё.

Например, мне нужно было привыкнуть к iOS-эмулятору. В то время как выполнение, средствами командной строки, команды react-native run-ios, кажется делом обманчиво простым, в самом начале работы простого вызова этой команды было недостаточно для того, чтобы эмулятор нормально заработал. Так как в проект почти ежедневно добавлялись новые npm-пакеты (а позже — и немало нативных модулей CocoaPod), я, куда ближе, чем мне того хотелось бы, вынужден был познакомиться с неприятным ритуалом очистки ресурсов Watchman и кэша Haste, удаления папки node_modules, переустановки модулей и сброса кэша Metro Bundler. Все эти задачи, к счастью, можно решить с помощью следующей команды:

watchman watch-del-all && rm -rf tmp/haste-map-react-native-packager && rm -rf node_modules && yarn && npm start --reset-cache


В 9 из 10 случаев подобный «танец с бубном» позволял вернуть эмулятор к жизни. Иногда, правда, даже этого было недостаточно. Тогда приходилось углубляться в описания сообщений об ошибках на GitHub и вчитываться в обсуждения на StackOverflow.

Корнем некоторых других проблем был тот факт, что я долгое время полагал, что для того, чтобы решить некоторые задачи, необходимо было запускать Xcode. И, уж поверьте, вы будете стремиться к тому, чтобы пробыть в этом доме ужасов IDE как можно меньше времени.

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

react-native run-ios --simulator=’iPhone X’


В качестве других примеров сложностей привыкания к новой среде разработки можно назвать трёхступенчатый процесс подготовки релиз-версии приложения (для размещения в App Store или в некоей среде непрерывной интеграции, вроде Visual Studio App Center или Firebase) и процесс перехода от релиз-версии к версии, предназначенной для отладки (к режиму разработки). Возможно, многим очевидным покажется то, что необходимые изменения в проект можно внести с помощью любого текстового редактора. В любом случае, это лишь пример пары мелочей, которые оказали неожиданно большое воздействие на мой рабочий процесс при работе в режиме разработки.

И наконец, некоторое время заняло привыкание к необходимости постоянного переключения между различными macOS-приложениями, необходимыми для решения тех задач, которые я, разрабатывая веб-приложения, обычно решал средствами одного лишь Chrome.

Для того чтобы смотреть то, что JavaScript-код пишет в консоль, и анализировать, в целях отладки, выводимый HTML/CSS-код, я обратился к React Native Debugger. Для того чтобы наблюдать за состоянием приложения, за отправленными действиями, за запросами к API и полученными ответами, я использовал Reactotron. Хотя я нашёл оба этих приложения чрезвычайно полезными, я не мог не думать о моём привычном рабочем процессе, применяемом при создании Ember.js-приложений, когда я мог решать все эти задачи в той же среде, в которой выполнялись мои приложения (с помощью плагина Ember Inspector для Chrome).

Навигация


Организация навигации/маршрутизации, по всей видимости, представляет собой весьма сложную задачу для React Native. За время существования этого фреймворка появилось множество различных решений этой задачи, но всё ещё нет чего-то такого, что можно было бы назвать общепризнанным эталоном. Я решил использовать библиотеку react-navigation, на мой выбор повлияло в основном то, что об этой библиотеке рассказывали в курсе по React Native, который я прошёл, а также то, что ей пользовались мои коллеги.

Если бы я вложил некоторое время в достаточно глубокое изучение этого вопроса, я мог бы выяснить следующее:

  • У проекта react-navigation имеется примерно 15000 звёзд на GitHub и 86 нерешённых проблем. Он полностью основан на JavaScript и отличается наиболее подробной документацией среди виденных мной решений для навигации.
  • Библиотека react-native-navigation набрала около 10000 звёзд, у неё оказалось 162 нерешённых проблемы. В ней, однако, используется не только JavaScript. Для работы с ней нужно редактировать нативные файлы.
  • Репозиторий react-router является обладателем примерно 35000 звёзд и списка из 55 нерешённых проблем на GitHub. Правда, эти показатели нельзя напрямую сравнивать с другими описываемыми тут проектами, так как в данный репозиторий входят пакеты, предназначенные не только для React Native, но и для React.
  • Проект native-navigation имеет около 3000 звёзд и 55 нерешённых проблем. Тому, кто собирается его изучить и использовать, стоит учитывать то, что он всё ещё находится в состоянии бета-версии, то, что в нём используется не только JavaScript, и то, что его поддержкой занимается Airbnb (эта компания решила отказаться от React Native).


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

После того, как я проработал с react-navigation примерно 9 месяцев, я должен сказать, что мне особо не на что жаловаться. Если сравнивать эту библиотеку с привычной мне библиотекой router.js, используемой в Ember.js, я могу отметить, что это — нечто совершенно новое.

Мне было совсем несложно разобраться с тремя основными типами средств навигации react-navigation. Это — StackNavigator, TabNavigator и DrawerNavigator. Куда сложнее было понять то, как эти средства совместить для того чтобы создать необходимую мне систему навигации по приложению.

Например, то, что компонент DrawerNavigator должен быть корневым элементом системы навигации (на одну ступень выше главного компонента TabNavigation), было для меня совершенно неочевидным. Если это трудно представить — вот как выглядит DrawerNavigator в действии (в реальном приложении всё работает гораздо более плавно).

592c1bef296cfa6b46a6e3fb82ee03b6.gif


DrawerNavigator из react-navigation в действии

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

Я воспринимал боковую панель как нечто второстепенное по сравнению с основной навигационной панелью, расположенной в нижней части приложения. Поэтому мне казалось, что DrawerNavigator нужно поместить в дереве маршрутов (оно показано ниже) либо под основным BottomTabNavigator, либо на том же уровне, что и этот элемент.

Однако после того как я изрядно помучился, пытаясь насильно впихнуть боковую панель туда, где ей, как оказалось, не место, я понял, что, в соответствии с особенностями react-navigation, DrawerNavigator нужно поместить на одну ступень выше BottomTabNavigator, то есть — в корень дерева навигации. Я надеюсь, что эта моя находка поможет кому-нибудь из читателей данного материала сэкономить время, которое иначе было бы потрачено на чтение документации и материалов на GitHub.

Вот как выглядит дерево навигации приложения. Здесь, в качестве корневого элемента, используется MainDraverNavigation.

5677f3e7d38ff88e7c3b9db7865a96c0.png


Итоговое дерево навигации первой версии приложения

Тут вы можете задаться вопросом о том, зачем, для разделов Community и Conference, нужны и StackNavigator, и TabNavigator. Нельзя ли просто опустить слой StackNavigator и перейти сразу к TabNavigator?

Дело в том, что мне нужно было, чтобы у каждого из двух элементов TabNavigator был бы заголовок. Вот они.

dc4602dd6122f63d13ec162de4f72a9c.png


TabNavigator, заголовок

Тут, снова, мои догадки не соответствовали устройству react-navigation. Я полагал, что MaterialTopTabNavigator должен быть совершенно обычным навигационным компонентом, поэтому решил, что в его настройках должна быть некая встроенная опция, позволяющая задавать заголовок. Как оказалось, ничего такого там не было, и именно поэтому я вынужден был использовать, в качестве промежуточного слоя, StackNavigator, добавляя, в результате, дополнительный уровень сложности в инфраструктуру приложения и руководствуясь довольно-таки «косметическими» соображениями.

Этот недостаток react-navigation, кроме того, причинил мне гораздо более серьёзные неприятности. В частности, они заключались в необходимости организовать сворачивание и исчезновение заголовочного изображения в ходе прокрутки пользователем списка элементов, организованного средствами FlatList. Так как заголовки разделов Home и Selection выводились в пределах того же самого элемента StackNavigator, что и списки их элементов, эту проблему было бы несложно решить, просто позволив заголовку прокручиваться вместе с остальными элементами списка.

Но вот в случае с разделами Community и Conference я не смог найти способа применить то же решение, так как заголовки выводятся средствами элементов StackNavigator, а списки — с помощью элементов TabNavigator, на одну ступень выше в дереве навигации. В результате я отказался от прокрутки заголовка, что внесло в приложение неприятную неоднородность.

12c32d323e8cc657fcb79db8fe8c36dc.gif


Прокрутка в TabNavigator и StackNavigator

Хотя в эмуляторе, имитирующем Iphone X, описываемая проблема с заголовком серьёзной и не кажется, на экране маленького размера заголовок может занимать около 20% доступного экранного пространства. Если кто-нибудь знает о том, как эту проблему решить — дайте мне знать.

Та же самая проблема с TabNavigator дала о себе знать и в разделе Destination. Как будет показано на следующем рисунке, справа, я хотел поместить другой элемент TabNavigator на вкладку Coworking Spaces для того, чтобы вывести три верхних закладки Info, Members и Contact.

При работе с TabNavigator сложно было поместить слайд-шоу в верхней части элемента без того, чтобы не усложнить решение и не вызвать множество проблем с навигацией (в основном связанных с параметрами навигации). Поэтому мне пришлось прибегнуть к JS-пакету, который называется react-native-swiper для того, чтобы работать с этими тремя вкладками. Надо отметить, что меня это решение полностью устроило бы в том случае, если бы его применение не приводило бы к скачкообразной анимации линий, подчёркивающих заголовки вкладок. В любом случае, я счёл этот недостаток справедливой платой за возможность избежать проблем с альтернативной системой навигации.

0e4980e20485e339e8f0ce13ea634db4.gif


Сравнение TabNavigator из react-navigation с react-native-swiper (обратите внимание на разницу в анимации золотистых линий, находящихся ниже названий вкладок)

Вот какие выводы я сделал после реализации подсистемы навигации приложения:

  • Есть множество хорошо документированных решений, предназначенных для организации навигации в React Native-приложениях, среди которых я выбрал react-navigation. Оно наилучшим образом удовлетворяет моим нуждам.
  • Библиотека react-navigation значительно упрощает начало работы над проектом в том случае, если разработчик не особенно много знает о том, как работают системы навигации мобильных платформ.
  • Библиотека react-navigation имеет некоторые особенности, которые не отличаются интуитивной понятностью (по крайней мере для веб-разработчика), но в ней нет ничего такого, чего нельзя бы обойти, пусть и не самым эффективным образом.


Экран-заставка


Запуская в эмуляторе новое приложение, созданное средствами команды react-native init, постоянно перезагружая его по мере внесения в него изменений, очень быстро понимаешь то, что приложению нужен симпатичный экран-заставка (их ещё называют «сплэш-скринами»).

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

d8145d91a9f279584dd9985ad6503abe.jpg


Экран-заставка, с которым возникла проблема

Эта проблема проявляется в редких случаях на iOS, но с ней, наверняка, столкнутся некоторые пользователи приложения. Впервые я обнаружил эту проблему тогда, когда работал в одном месте, где не мог пользоваться WiFi и подключил ноутбук к 4G-интернету через телефон. Пользователи iPhone знают, что когда телефон раздаёт интернет, его статус-бар окрашивается в синий цвет и становится выше. Это «поломало» изображение на моём экране-заставке когда я запускал приложение на телефоне. Та же проблема возникала и при вызове.

В результате я, порывшись некоторое время в репозитории react-native-splash-screen и не найдя там ничего полезного, решил обойти эту проблему, полностью скрыв строку состояния во время показа экрана-заставки.

Это очень просто — достаточно добавить в файл info.plist ключ UIStatusBarHidden, присвоив ему логическое значение true, а затем, после вызова SplashScreen.hide(), установить в значение false свойство hidden компонента React Native StatusBar.

Управление состоянием


У меня такое ощущение, что последние два года я каждый день слышу о приоритете соглашения над конфигурацией, о принципе Convention over Configuration (CoC). Так было и на моей предыдущей работе. И это неудивительно, так как там мы, на сервере, использовали Ruby on Rails, а на клиенте — Ember.js — два фреймворка, суть которых как нельзя лучше соответствует принципу CoC. Я думал, что я знаю о том, что это значит, но процесс изучения управления состоянием в React Native дал мне совершенно новое понимание этого принципа.

Хотя я, в нескольких очень простых приложениях, и экспериментировал с библиотекой React, на которую повлиял этот принцип, я никогда не создавал на её основе чего-то достаточно масштабного, такого, что позволило бы мне оценить достоинства использования контейнеров состояния наподобие Redux или MobX. Большая часть моего опыта управления состоянием JS-приложений касается Ember Data (это — встроенная в Ember система для управления состоянием и организации постоянного хранения данных).

Так как библиотека Redux представлялась мне одним из лучших решений проблемы управления состоянием, о котором я слышал уже многие годы (и о котором говорилось в курсе по React Native, пройденным мной), я, в общем-то, и не смотрел в сторону её конкурентов. Мне просто хотелось оснастить своё приложение наилучшей из существующей систем управления состоянием и сделать это без лишних усилий.

В Ember 90% инфраструктуры для работы с данными оказываются в руках программиста уже готовыми к использованию. Я и не подозревал, что в моём текущем проекте всё будет с точностью до наоборот. Как оказалось, ничего полезного для поддержки глобального состояния не даёт не только React, но и Redux — самая популярная библиотека для управления состоянием. Эта библиотека настолько легковесна, что программисту приходится брать на себя 90% забот по работе с данными внутри приложения для того чтобы создать достойную систему управления состоянием.

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

  1. Добавить в файл с константами три константы: SOME_ACTION_REQUEST, SOME_ACTION_FAILED, SOME_ACTION_SUCCEEDED.
  2. Добавить создатель действия в файл действий.
  3. Обработать три действия в подходящем редьюсере, и, если нужно, добавить в систему новый редьюсер и включить его в корневой редьюсер.
  4. Добавить воркеры в подходящую сагу, и, если нужно, добавить в систему новую сагу и включить её в корневую сагу (я, для обработки асинхронных действий, использую библиотеку redux-saga).
  5. Добавить функцию для обработки любых возможных запросов к API.
  6. Сделать маппинг необходимых данных из состояния в свойства в соответствующем React-компоненте.
  7. Отправить действие SOME_ACTION_REQUEST из соответствующего React-компонента.


Redux и redux-saga, конечно, обладают гораздо более обширными возможностями, но, учитывая то, что меня в настоящее время интересует, представленные выше 7 шагов — это то, чем для меня является Redux.

Сессии


Итак, мы настроили среду разработки для React Native-приложений, создали дерево навигации, подготовили инфраструктуру управления состоянием. Что хорошо будет сделать на следующем шаге работы над проектом? Для меня совершенно естественным ответом на этот вопрос стало создание системы аутентификации пользователей. Поэтому сейчас мы поговорим о сессиях.

Если вы пришли в сферу React Native из веб-разработки, то вы разберётесь с сессиями без особого труда. Если вы хотя бы немного знакомы с концепциями, на которых основано хранилище LocalStorage, то вам достаточно знать, что при работе с React Native обращение к подобному хранилищу нужно заменить на обращение к AsyncStorage. Это — уровень абстракции, который позволяет хранить данные в формате ключ-значение в перерывах между сессиями. Другими словами, тут можно хранить сгенерированный на сервере токен аутентификации, переданный на клиент после успешного входа пользователя в систему.

Списки


Если говорить о работе со списками, то у меня возникло такое ощущение, что в React Native эта задача решена достаточно хорошо. В целом можно отметить, что у разработчика есть три возможности. Если он работает со статическими списками, данные, представленные в которых, не меняются, то ему, скорее всего, хватит возможностей ScrollView. Если работать надо с более длинными списками, которые, к тому же, являются динамическими, тогда стоит присмотреться к FlatList. Если же речь идёт об ещё более крупных списках, которые, кроме того, могут быть разделены на разделы, тогда полезно будет прибегнуть к возможностям SectionList.

Я, для динамических списков, использую исключительно FlatList. И хотя мне, на интуитивном уровне, нравятся эти списки и возможности по их конфигурированию, я, при работе с ними, столкнулся с несколькими неприятностями. Сейчас я о них расскажу.

▍Протяжка списка для обновления его содержимого


У компонента FlatList имеется свойство, которое называется refreshControl. С его помощью можно передать этому компоненту компонент, который нужно использовать для обновления содержимого списка, выполняемого в том случае, когда пользователь протягивает список, находясь в его верхней части. К счастью для нас, в React Native имеется компонент, предназначенный специально для решения этой задачи. Это — RefreshControl. Кажется, что всё здесь в этом плане устроено просто и понятно.

3ce4cecd286b9c56011091d2bad71fd4.gif


Компонент RefreshControl в действии

Однако тут я столкнулся с одной странностью, причиной возникновения которой, как казалось, было либо свойство refreshControl, либо компонент RefreshControl, а может и то, и другое. Итак, мне нужно, чтобы при работе со списком пользователь мог бы выполнять следующие действия:

  • Он должен иметь возможность потянуть список вниз, находясь в его верхней части, для того чтобы обновить содержимое списка. Обновление планировалось выполнять с помощью функции, которую я назвал handleRefresh().
  • Когда пользователь прокручивает список и доходит до его конца, автоматически должны были загружаться дополни

    © Habrahabr.ru