Статья ориентирована на iOS и android разработчиков, которые уже достаточно хорошо разбираются в своей области и поглядывают в сторону React Native.

Впервые узнав про React Native, я воспринял его как повод для веб-разработчиков вторгнуться на мою территорию (нипазволю!) и заодно испортить хорошо работающий crash-free-60-fps продукт. Так оно и произошло. Конец. Реальная история оказалась длиннее.

Отрицание


JavaScript в мобильном приложении? В голову приходило всего пара библиотек с использованием JavaScriptCore на iOS (эти же библиотеки были причиной 90% падений приложений, в которых использовались) и гибридные приложения “старого образца” (ну это вообще атас).

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

Вспоминая неудачные потуги в освоении Xamarin 3 года назад я быстро отказался от идеи использовать React Native.

Стоит отметить что я всегда с радостью воспринимал новые способы написания нативных приложений (от ObjC к Swift, от Java к Kotlin, от Eclipse к Android Studio). Уже много лет занимаюсь iOS и android разработкой в качестве хобби и профессионально. После перехода на новый язык (внутри одной ОС) или IDE я редко возвращался к предыдущему. Казалось бы React Native — логичный следующий шаг, ещё одна новая ступень вверх. Или это шаг назад?

Гнев


К чему мне учить упрощённый вариант, когда я уже знаю как делать это “по-настоящему”?!
На этот вопрос мне ещё предстояло найти ответ когда компания поставила задачу полного редизайна одного из приложений (в тот момент доступного только на iOS) и выпуска его на android.

Как сделать сразу два дела и написать меньше кода? Напрашивались решения вроде: тонкий клиент, библиотеки на C с вызовом из Swift / Kotlin кода, React Native?

React Native выглядел довольно перспективно из-за возможности сделать библиотеки и затем использовать их сразу на трёх платформах (iOS / android / web).

Торги


Перспективно для кого угодно, но только не для меня. Я точно не был счастлив такому повороту. Чувствовал что нахожусь на пике способности к развитию iOS и android и тут меня попросили выбросить все эти знания, как будто я свежий выпускник и опыта у меня 0. Ещё больше я сомневался в том что с React Native можно создать качественный продукт.



Депрессия


Сомнение были обоснованными. Главные проблемы:

  • приличное количество падений в ядре React Native;
  • методы, которые работают только на одной платформе (в доках указано что работают везде);
  • неполное описание. Вы только взгляните на доки сборщика React Native.

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

Принятие


И конечно React Native — это не только минусы. Есть много хорошего, пишется это намного проще и работает из коробки лучше чем тоже самое на конкретных платформах.

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

JavaScript


Ничего удивительного. Это первое с чем придётся идти рука об руку через кровь, пот и слёзы.
Когда я начал вспоминать свой предыдущий опыт frontend-разработчика (до мобильных приложений занимался сайтами), у меня начался вьетнамский синдром: Джонни, JavaScript нас окружает!

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

В последние несколько лет с выходом стандартов ES6, ES7 и ES8 способ написания кода сильно изменился.

И он стал очень даже ничего.

Статическая проверка


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

Есть разные утилиты, которые сглаживают его отсутствие, выполняя часть функций

Вёрстка элементов


Самым большой вызов здесь будет для начинающих iOS разработчиков.

Этот вызов — отсутствие визуального редактора интерфейса.

Всё делается в коде с помощью JSX-разметки. Технически, эта разметка не обязательна, она помогает увидеть иерархию компонентов. Android-разработчики будут в своей тарелке, заметив сходство с XML.

Одновременно есть понятный вид вьюшек и потенциал для переиспользования.

В iOS нет либо одного либо другого, зависит от того какой метод выбрать (вёрстка в коде или в Interface builder). Да, обе эти проблемы решаемы, но приходится писать приличное количество кода.

В React Native нет этой проблемы.
В Android, кстати, её тоже нет.
Зато Android-специалисты оценят способ передачи параметров из внешних компонентов во внутренние прямо в разметке.

Базовые View здесь — аналог LinearLayout (android) и UIStackView (iOS) с примесью констрейнтов одновременно. Довольно простой способ (по сравнению с констрейнтами) позиционирования элементов.

UIViewController и Activity


В React Native нет ни того ни другого.
Конечно они есть под капотом. Напрямую взаимодействовать с ними не получится. Да это и не нужно.

Жизненный цикл всех React Native компонентов полностью отличается от iOS и android, сложно провести какие-то параллели. Если сосредоточиться на отличиях от нативных систем, то:

  • UI-элементы сами меняют состояние / вид при изменении входных параметров;
  • на android нет необходимости жонглировать onSaveInstantState. React Native всё это делает за нас;
  • на iOS нет методов, которые напрямую явно сообщают момент появления / скрытия экранов приложения.

Время сборки / Live Reload / Hot Reload


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

Все изменения в JS-коде видны сразу видны в симуляторе. Колоссально ускоряет разработку!

Отсутствие нативного функционала в JS


В JS-части React Native из коробки доступно не всё что нужно.

Можно написать нативную часть на обе платформы, сделать JS-обёртку и вызывать её как остальной код. Ничего сложного нет.

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

Все модули подключаются через npm (аналог CocoaPods для iOS и Gradle для android), в которых есть нативный код с нужным функционалом.

Универсальные и глубокие ссылки


Функционал реализован силами Facebook.
Работает хорошо и консистентно.

Обработка сторонних Intent’ов


Как частный случай предыдущего пункта.

Самая большая проблема на android — обработать Intent, отличный от диплинка в приложение.
Зависит, конечно, от Intent’а и что необходимо сделать при его получении.

На эту тему можно написать отдельную статью. Стартовая точка — добавить метод createReactActivityDelegate в MainActivity.

Производительность


Довольно просто получить 60 FPS при прокрутке длинных списков со сложными ячейками.
Производительность всего остального (например — нажатие на кнопку, печать текста в поле) ниже. Заметно при анимированной смене состояния у большого количества элементов. С этим можно легко бороться. Хороший раздел в документации Using Native Driver for Animated.

А ещё из коробки нельзя получить нормальное управление жестами и их связывание с анимацией.



Нестабильность


Часто проект просто прекращает собираться, например после:

  • обновления ядра React Native (в том числе при обновлении минорной версии);
  • обновления npm-модулей;
  • обновления XCode;
  • обновления CocoaPods (с этим вообще постоянные проблемы);
  • просто так. Да, такое тоже бывает.

К счастью большинство этих проблем довольно быстро исправляются. Можно добавить скрипт, который чистит все кеши везде, и запускать его когда что-то идёт не так. Помогает решить 98% странных проблем, возникших из ниоткуда. За исключением CocoaPods, тут всё печально.

Нестабильность сторонних зависимостей


Самой большой проблемой на iOS было и есть повсеместное желание npm-модулей использовать method swizzling.

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

Сборка происходит в несколько этапов и на каждом из них может что-нибудь пойти не так.

Нестабильность при обновлении сторонних зависимостей


Одни npm-модули зависят от других npm-модулей и так далее. Если два модуля завязаны на разные версии третьего модуля, то мы сразу получаем warning при установке, в лучшем случае. А в худшем случае warning'a нет, но ничего не работает.

Аналогичная проблема, если npm-модули полагаются на нативные Android-модули с разными версиями.

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

Unit и UI-тестирование


Очень лёгкий механизм тестирования через библиотеку Jest, идёт в комплекте к React Native. Удобный анализ покрытия тестами — показывает какие строки в тестируемой функции не вызывались ни разу.

Есть библиотеки для UI-тестирования. Пока на деле не пришлось использовать.

Заключение


Спустя 13 месяцев работы с React Native могу с уверенностью сказать:

  • он подходит для большинства приложений, в которых надо просто получить с сервера список, показать список, показать подробный вид элемента списка, отправить на сервер изменения;
  • всё перечисленное выше достигается меньшим количеством кода;
  • теперь это мой выбор “по умолчанию” для новых проектов, с которыми ко мне обращаются, потому что см. предыдущий пункт;
  • не подходит для проектов, выходящих за границу “отправил запрос — получил ответ”, немного примеров: фоторедактор, плеер, работа с Bluetooth, AI, ML, соц. сеть, мессенджер;
  • advanced-проекты можно сделать на React Native, но всё равно придётся писать много нативного кода, поэтому смысл отпадает;
  • React Native пришёл и никуда не денется, с этим надо считаться;
  • спрос на нативных мобильных разработчиков несколько снизится, приток новых нативных мобильных разработчиков снизится намного больше. Почему? см. ниже;
  • человек как правило идёт по самому простому пути, и незачем стараться, если 95% приложений можно сделать, потратив 20% усилий (по сравнению с нативной разработкой) на изучение;
  • как следствие из предыдущих трёх пунктов: разрыв между спросом и предложением нативных мобильных разработчиков станет ещё больше. Тем, кто действительно не может без них обойтись, будет ещё труднее их найти. И это печально.

Заключительное слово для того, кто сразу начал писать на React Native и по каким-то причинам решил прочесть эту статью, ещё и до самого конца.

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

Комментарии (24)


  1. zaqqq13
    04.07.2018 00:38

    Я бы не стал так обобщать. Реакт очень удобен для создания мелочей вроде мобильного клиента какого-либо сайта, плюс с минимальным количеством нативного кода можно неплохой функционал реализовать, так какой смысл писать полностью нативное приложение с тем же функционалом? Как пример — работа с bluetooth, конечно, ради нее можно все приложение писать дважды — под андроид и яблоко, а можно набросать шаблон на реакте, а само взаимодействие с bluetooth реализовать в виде небольшой подключаемой нативной либы, чем плох подобный подход?


    1. Guitariz
      04.07.2018 08:37

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


      1. zaqqq13
        04.07.2018 09:08

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


        1. Guitariz
          04.07.2018 09:21

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


          1. zaqqq13
            04.07.2018 09:27

            Так никто и не спорит что везде есть минусы, не бывает идеального инструмента, но для лентяев вроде меня РН в принципе неплохой вариант)


          1. VolCh
            04.07.2018 11:56

            Разработка мобильных приложений как бизнес-задача может быть поставлена по принципу «у всех есть, нам тоже надо» или как проверка маркетинговой идеи, рабочий прототип: станет популярен, хотя бы сравним с количеством заходов на сацт с мобильных — начнём вылизывать, а нет -так закроем вообще. Тут заставлять того же фронтендера тратить несколько месяцев на освоение платформ или нанимать спеца или двух может оказаться не очень разумным ходом.


            1. Guitariz
              04.07.2018 12:16

              Кроилово всегда ведет к попадалову.


  1. CRivlaldo
    04.07.2018 08:19

    не подходит для проектов, выходящих за границу “отправил запрос — получил ответ”, немного примеров: фоторедактор, плеер, работа с Bluetooth, AI, ML, соц. сеть, мессенджер;

    На ReactNative еще не писал. Почему не подходит для плееров? Объясните подробнее, пожалуйста.


    1. zaqqq13
      04.07.2018 09:13
      +1

      Потому что для взаимодействия с тем же системным декодером нужна нативная либа под конкретную платформу, а реакт ее не предоставляет. Хотя есть способы написать нативную либу и обернуть ее в модуль под React Native, но смысл такого действия сомнительный — все равно вы по сути пишете один и тот же функционал под разные платформы. Тут надо скорее смотреть на конкретный сценарий использования инструмента. Если вы пишете один условный плеер, то вам нет разницы на чем писать — в любом случае будете под каждую платформу большую часть функционала реализовывать нативными средствами. Но если у вас фирма, которая пишет условные плееры на заказ, тогда вам имеет смысл оформить базовый функционал в виде модулей под реакт для последующего использования)


      1. CRivlaldo
        04.07.2018 09:29

        Правильно ли я понимаю, что нужно написать две нативные либы для работы со звуком и обернуть их? Таким образом, в данной ситуации выгода использования ReactNative – это общий код UI и бизнес логики, верно?


        1. zaqqq13
          04.07.2018 09:42
          +1

          Ну типо того, плюс набор багов на каждой конкретной платформе, которые надо фиксить


  1. Guitariz
    04.07.2018 08:35

    Полтора месяца разрабатывал на RN. Нерешенные на сегодняшний день проблемы:

    • никакущая стабильность.Заставить приложение не падать — большой квест, особенно когда у тебя больше 5 экранов. Обновление версии языка — игра в русскую рулетку.
    • сборка. Добавляешь одну либу — тянется десяток зависимостей — перестает собираться вообще все. Начинаешь выставлять зависимости — обнаруживаешь, что либы ссылаются на самые нестабильные ветки — беты, эксперименталы и пр. Запускаешь билд на другой платформе (скажем, тестировал на иос, собираешь андроид) — повторяешь квест. И так можно до бесконечности
    • само по себе наличие библиотек в бете (впрочем, как и самого языка) — отсутствие гарантий в разработке релизных продуктов
    • графические артефакты и уникальные для платформы фичи. Сколько бы разговоров о мультиплатформе не было, текстовые поля отображаются по разному, в отрисовке теней вечно возникают артефакты. Верстать что-то простое можно, но ни об идентичности, ни о сколько-нибудь приемлемом виде верстки из коробки для сложных приложений речь даже не идет.
    • отсутствие нормальной связки с железом и особенностями оси. Да, все можно прикрутить в качестве либ, но тогда теряется время разработки, ухудшается стабильность. В итоге выйгрыша в сравнении с нативной разработкой уже нет.


    1. alex_tewpin
      04.07.2018 21:37

      никакущая стабильность.Заставить приложение не падать — большой квест, особенно когда у тебя больше 5 экранов. Обновление версии языка — игра в русскую рулетку.

      Не могу согласиться. Бывают проблемы на этапе сборки, но в рантайме, как правило, все хорошо. За последний месяц у нас 100% crash-free users. Экранов уже десятки.


  1. yul
    04.07.2018 09:12
    +1

    NativeScript не рассматривали? Или, может, кто-нибудь может поделиться собственным опытом? Непросто найти отзывы о реальном применении в более-менее серьезных задачах.


  1. faiwer
    04.07.2018 10:24

    Вопрос к тем, кто активно работал с React Native. Я читал, дескать, там неплохо реализована поддержка FlexBox. А как насчёт inline + inline-block? Для одного из проектов, которые моя контора планирует реализовать на RN это очень критично. Т.е. нужна удобная возможность иметь строчную и строчно-блочную вёрстку. Условно это когда содержимое одного <span/> может начинаться в произвольном месте одной строки, занять ещё 3, и на 5-ой закончиться где-нибудь в середине, и при этом в этом же контексте могут быть блочные элементы. В общем речь про display: inline & display: inline-block.


    Ещё вопрос: а как там с поддержкой SVG? Есть сложные интерактивные графики функций, с drag-n-drop-ом, установкой точек на канве, и прочими штуками, которые не во всех браузерах поддерживаются.


    1. Guitariz
      04.07.2018 12:17

      В нем плохо реализована поддержка ВСЕГО. Язык до сих пор именно поэтому в бете.


    1. papercuter
      04.07.2018 14:50

      У React Native огромное сообщество, которое постоянно растет и реализует различные библиотеки, в том числе подходящие под Ваши задачи. Первое, что приходит в голову, это рендерить html, например используя следующий компонент: https://github.com/jsdf/react-native-htmlview


      Что касается SVG, то тут посложнее, но, думаю, найдется и что-то подобное. Опять-таки никто не мешает написать нативно и обернуть в JavaScript.


      1. faiwer
        04.07.2018 14:57
        +1

        Спасибо за ссылку. Увы, в таком случае проще сразу взять WebView или весь проект писать на Cordova. HTML не годится. Нужна именно полноценная поддержка inline-layout-ов.


    1. alex_tewpin
      04.07.2018 21:29
      +1

      Я читал, дескать, там неплохо реализована поддержка FlexBox

      Это не вполне так, за лейаут в RN отвечает yoga у которой нет цели реализовать спецификацию CSS flexbox. Он похож, но не совсем. Такого понятия как display: inline в нем не существует. Разве что заворачивать каждое слово в свой контейнер и ставить flex-wrap.

      Ещё вопрос: а как там с поддержкой SVG?

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


  1. Fragster
    04.07.2018 12:30

    А кто что думает про cordova.apache.org? Думаю попробовать начать разработку чего-то мобильного именно со связки vue+cordova :)


    1. ZAMnoTEX
      04.07.2018 13:05

      Кордова еще не умерла? В одной конторе, где я работал разработчиком Xamarin, проект раньше был написан на Cordova, но код был отправлен в помойку и переписан на Xamarin


      1. Fragster
        04.07.2018 13:14

        Просто недавно как раз увидел вопрос на тостере, там рекоменловал в тч такой вариант. Ну а по мануалам на офсайте всё, вроде бы, не сложно.


        1. ZAMnoTEX
          04.07.2018 13:56
          +4

          Cordova имеет еще больше ограничений, чем ReactNative. И хуже производительность. Там же WebView под капотом. А по мануалам на оф.сайте — так это любой фреймворк прекрасен!


    1. GamePad64
      04.07.2018 14:39

      Для мобильного с Vue есть смысл попробовать nativescript-vue, если хочется именно приложение.
      Либо делать на нём PWA, которое будет работать в WebView без Cordova.