5 подводных камней при разработке на React Native

Article in English: https://medium.com/p/7b9b7872e856

На моей нынешней работе мы пишем большую социальную сеть как SPA с использованием React. Большую часть времени я работаю именно с яваскриптом. То есть, когда я увидел, что существует технология для разработки мобильных приложений для iOS/Android на JS, я как-бы естественно решил, что это очень круто — писать на одном языке и тут и там. Опыт есть, знание подводных камней есть. Почему бы и нет? Плюс сразу приложение для двух платформ. Кто бы отказался?

Спустя полгода работы с React Native я обрел кое-какое понимание и обнаружил несколько моментов, которыми хотел бы поделиться с вами.

1. Знания одного JS вам не хватит для серьезного приложения

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

На JavaScript можно написать 100% кода мобильного приложение, но только для маленьких и типичных приложений! Когда нужно знание нативных языков:

Когда нужно больше возможностей чем может дать JavaScript:

Работа с возможностями мобильной платформы реализуется благодаря модулям на нативных языках.

Давайте возьмем простой пример, вам нужно найти нативный модуль, который будет позволять загружать файлы в фоне (когда приложение свернуто)

Стандартных возможностей Fetch API на React Native не хватит для реализации этой задачи

После непродолжительного поиска я нашел модуль, который поддерживает как Android так и iOS:

Pull Request в Open Source (доработка библиотеки)

Я выбрал эту библиотеку, потому что я считаю, что это лучшее решение, но которое необходимо доработать, а именно реализовать multipart/form-data загрузку файлов на сервер.

Есть два способа получить необходимый функционал в open source проекте:

Запросить нужную возможность у разработчиков библиотеки

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

Сразу скажу, я не любитель языка Objective-C, потому что это “non standard” язык программирования для меня.

Мой выбор — потратить немного своего времени на разработку необходимых мне возможностей и получить результат в кратчайшие сроки. Кстати, не так сложно дорабатывать необходимый функционал для Android на Java/iOS на Objective-C:

2. Нативные компоненты выглядят по разному на платформах

К примеру, вам потребуется сделать dropdown/select для того, чтобы пользователь мог выбрать язык на котором он говорит.

В документации для React Native вы найдете компонент Picker, после добавления его в ваше приложение вы заметите разницу в отображении на разных платформах:

Слево-iOS, справа-Android.

Еще один момент, в процессе работы над GHubber, мне нужно было отоброзить список коммитов для выбора, я нашел компонент Alert

Слево: Android, справо: iOS.

Но на Android, существует ограничение в отображении Alert компонента, можно выбрать только три кнопки: positive, negative and neutral.

3. Верстка приложения != верстка сайта

В React Native верстка компонентов реализуется на основе философии FlexBox благодаря кроссплатформенному фреймворку Yoga. Стили компонентов максимально приближены к тому что мы привыкли видеть в Web, но увы, это не является вебом и в процессе разработке вам придется познать некоторые особенности.

4. Нативный код может тоже упасть :(

В любом софте есть баги, и первым делом вы должны установить инструмент который будет помогать вам отлавливать их, но не стоит забывать что есть ошибки в JavaScript, а есть и нативные. У себя в проектах я использую Sentry потому что:

  1. Open source software
  2. Большое кол-во интеграций со всевозможными платформами (browser/nodejs/php/android/ios/react-native и т.д. )
  3. Поддержка source maps and dsyms
  4. Можно запустить Docker, Docker наше все ❤️

Вот нужная нам интеграция для React Native:

Все крайне просто в установке этого модуля, но смешным фактом будет, что в этом модуле тоже могут быть баги :D

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

Самыми важными вещами для того что бы не допускать ошибки в вашем мобильном приложении, это начиная с первого коммита;

  1. Строго использовать Flow везде
  2. Писать Unit тесты
  3. Не забывать, что существует ESLinter

5. Не забывайте, React Native — относительно молодая технология

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

Рассмотрим два последних релиза:

0.47 (последний на 1 August, 2k17)

Не все Open Source модули успевают обновиться для поддержки совместимости с новой версией React Native. Иногда вам приходиться помогать им в этом:

0.46

К сожалению, некоторые модули могут использовать закрытый API из внутренностей React Native, который без предупреждения может меняться каждую версию. Хорошая практика, это использовать только публичный API, ибо это гарантирует некую защиту от изменений в новых версиях.

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

Для примера, я возьму модуль RealmJS (база данных для мобильных приложений):

Как только я обновился до RN 0.46, я увидел этот страшный экран 😠

Если вы не нативный разработчик мобильных приложений, то вы скажете WOW, OMG, Stop it please 😠

Когда вы сталкиваетесь с исключениями или аварийными завершениями работы приложения (segfault), не тратьте ваше время на различные изменения вашей программы в поисках ошибки. Что стоит сделать, так это открыть XCode/Android studio и расставить break points, для того что бы отловить ошибку

Можно добавить еще try/catch 😜

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

В React Native 0.46 уже не существует метода executeBlockOnJavascriptThread, хотя RealmJS пытается/может использовать его благодаря этому хаку (interface RTCBridge):

Просмотрев коммит, я понял, что теперь стоит использовать метод ensureOnJavaScriptThread, но так-как я не core разработчик React Native, я решил спросить совета у Pieter De Baets (core developer of React Native) 😺

GitHub это в первую очередь социальная сеть, не бойтесь попробовать попросить помощи или совета в комментариях/задачах или просто задайте вопрос разработчику с помощью @
Спасибо большое Pieter De Baets 🍻 🍰

Выводы

Мне очень нравится технология React Native, несмотря на указанные проблемы. Не бойтесь разрабатывать на React Native-в итоге вы получите мобильное приложение под разные платформы используя 90% времени один java script.

P.S. Если вы собираетесь разрабатывать большое приложение на React Native, вам будет плюсом наличие хотя бы одного разработчика, который знаком с Android (Java) и iOS (Objective-C), который поможет вам в сложные моменты с багами / падениями или чем-то другим, что может оказаться сложным для JavaScript программиста

P.P.S. Мой опыт в разработке open source приложения на React Native (будет полезно посмотреть) https://github.com/ovr/ghubber

Если у вас есть вопросы или дополнения пишите в комментариях, с радостью отвечу!
Like what you read? Give Дмитрий Пацура a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.