Разбираемся, чем может быть полезен Mobile-разработчику React.js из веб-фронтенда.

Итак, React Native — это библиотека от Facebook для построения пользовательского интерфейса из компонентов, как стандартных, так и пользовательских. Интерес к этой библиотеке обусловлен сразу несколькими факторами: это кроссплатформенность, хорошая производительность и подход к построению UI, позволяющий легко разбивать интерфейс на независимые компоненты.

Немного предыстории

Все началось с появления библиотеки React.js в веб-разработке. Около 5 лет назад компания Facebook впервые начала использовать ее у себя в ленте новостей, затем к числу пользователей присоединился Instagram. В 2013 году исходный код библиотеки был открыт, и ее популярность стала стремительно расти. Сейчас React входит в топ-5 самых популярных библиотек на GitHub и широко используется за пределами Facebook (например, такими компаниями, как Airbnb, Netflix и Uber).

Можно выделить три основных особенности React, благодаря которым этот подход «выстрелил»:

Разбиение UI на независимые компоненты, которые можно повторно использовать. Вы можете легко определять свои компоненты как функции или, что чаще, классы, наследующиеся от React.Component и реализующие метод render(), который возвращает дерево из других компонентов. Компоненту сверху передаются данные в виде свойств (props), на основе которых он вычисляет дерево UI-элементов.

Важная архитектурная особенность React — это однонаправленный поток данных (англ. one-way data flow). Это означает, что компонент не может изменять переданные ему сверху props, а для обработки любых событий от интерфейса следует использовать функции-коллбэки, также передаваемые как props. Это полезное свойство позволяет избежать так называемого спагетти-кода. Таким образом, цепочка действий упрощенно выглядит так:

  • происходит событие UI (нажатие на кнопку);
  • компонент кнопки вызывает коллбэк onClick, переданный ему сверху;
  • из коллбэка выполняется некая бизнес-логика, изменяется состояние приложения;
  • происходит обновление UI посредством рендера корневого компонента с новым состоянием приложения, переданным в том или ином виде как props.

Screenshot_20170208_225219

Использование Virtual DOM. Применительно к мобильной разработке, термин не совсем корректный, но суть та же, что и в вебе — вместе с деревом элементов интерфейса, отображаемых на экране, в памяти строится его легковесная копия. При обновлении вычисляется diff между реальным и новым виртуальным деревом, и это позволяет обновлять на экране только те элементы, которые действительно изменились. В общем, этот подход позволяет упростить обновления UI до повторного рендера корневого компонента без тормозов и глюков.

В Facebook поняли, что этот же подход можно использовать для интерфейса мобильных приложений, и в 2015 году появился React Native, основанный на тех же принципах и имеющий набор типовых UI-элементов для мобильных приложений. Несмотря на малый возраст технологии, ее уже вовсю используют в продакшене. Приложения Facebook и Instagram — это React Native. Еще примеры реальных приложений — Airbnb, Bloomberg, JD.com, Discord, и это только наиболее известные.

Чем хорош?

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

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

Возможно, услышав слово JavaScript, вы подумали, что RN — это очередной метод завернуть браузер в приложение, но это не так. Слово Native в названии как раз указывает на то, что используются нативные элементы платформы — никакого HTML5. Тут будет очень кстати вариант Hello World из официальной документации, иллюстрирующий это свойство:

import React, { Component } from 'react';
import { Image, ScrollView, Text } from 'react-native';

class AwkwardScrollingImageWithText extends Component {
  render() {
    return (
      <ScrollView>
        <Image source={{uri: 'https://i.chzbgr.com/full/7345954048/h7E2C65F9/'}} />
        <Text>
          On iOS, a React Native ScrollView uses a native UIScrollView.
          On Android, it uses a native ScrollView.

          On iOS, a React Native Image uses a native UIImageView.
          On Android, it uses a native ImageView.

          React Native wraps the fundamental native components, giving you
          the performance of a native app, plus the clean design of React.
        </Text>
      </ScrollView>
    );
  }
}

Поэтому с производительностью здесь лучше, чем в решениях на основе WebView. Однако, нативные языки (Swift/Objective-C/Java) все равно будут быстрее, об этом ниже.

Еще один плюс — скорость разработки. Помимо лаконичного и выразительного синтаксиса (пример выше будет понятен любому разработчику), этому способствует так называемый Hot Reloading — пересборка и изменение UI без перезапуска приложения, с сохранением его состояния. Это возможно благодаря тому, что React в каком-то смысле представляет интерфейс как функцию от данных (состояния приложения). Не трогая состояние приложения, динамически заменяется код (JavaScript же!), отвечающий за UI, и интерфейс заново рендерится. На мой взгляд, это очень круто и удобно, особенно когда нужно в краткие сроки сделать реально работающий прототип приложения.

Ну и наконец, то, что тяжело или невозможно реализовать на RN, всегда можно реализовать нативным кодом.

А в чем минусы?

Безусловно, React Native — это не серебряная пуля ото всех бед, и у него есть заметные минусы.

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

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

Как ни странно, но в качестве минуса можно упомянуть… производительность. Да, RN быстрее, чем WebView, но все же медленнее нативного кода. Все дело в том, что на iOS движок JavaScriptCore не использует и не может использовать JIT-компиляцию ввиду того факта, что на iOS обычное приложение не может иметь участки памяти с разрешением на выполнение и запись одновременно. Напомню, что JIT-компиляция — это преобразование байт-кода в машинный на лету, во время выполнения программы, т. е. генерация исполняемого кода на лету, что в iOS невозможно. В JavaScript-движках JIT хорошо развит и позволяет в разы ускорить код, поэтому отсутствие JIT означает невозможность писать «тяжелые» вычисления на JS, и это опять приводит к необходимости написания нативного кода в некоторых случаях.

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

Заключение

Лично у меня сложилось положительное впечатление об этой технологии, так как ее подход выгодно отличается от решений вроде PhoneGap. Однако, несмотря на хайп вокруг этой библиотеки, нужно знать об ее недостатках и понимать, что в некоторых случаях этот вариант не подойдет. Будем надеяться, что React Native со временем избавится от своих «детских болячек» и сможет стать достойным конкурентом таким зрелым платформам, как Appcelerator, PhoneGap и Xamarin.

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.