Итак, пришла пора быстро погрузиться в тему. Для усиления эффекта, использую разные техники преобразования информации в знания. В частности, представляю конспект доклада Алексея Андросова (старшего разработчика интерфейсов, Yandex).
React Native — это фреймворк для разработки кроссплатформенных приложений для iOS и Android:
- появился в начале 2015 года
- построен на базе React
- не использует WebView и HTML-технологии
- нативные компоненты имеют биндинги в JS и обернуты в React
- поддержка iOS лучше, чем Android, но динамика многообещающая
Первый ли он? Нет!
- PhoneGap — реализация нативных компонентов на веб-технологиях, запускается в WebView
- Xamarin — от разработчиков Mono для Linux, приложения написаны на C# (проект купил Microsoft)
- NativeScript — похожие идеи, что и в React Native: XML + JS + CSS
Инструменты разработчика
- Ваш любимый редактор JS
- XCode и $100 в год на Developer account, чтобы собирать и публиковать приложения
- Терпение + Android Studio + SDK + Эмулятор
React Native: взгляд сверху
- Релиз примерно раз в 2 недели
- Все прелести early adopters: несовместимые изменения, stackoverflow driven development
- Все тот же обычный React
React Native: взгляд изнутри
- нет HTML, но есть компоненты платформы в JSX
- нет CSS, но есть CSS-like полифилы
- нет DOM API. Вообще. Совсем.
- ES6/ES7 и всё, что может babel, но нет JIT (на iOS)
Write once, run everywhere? Нет! Вместо ожидаемых предположений, что один и тот же код будем использовать многократно на разных платформах. Learn once, write everywhere. Одинаковая архитектура приложения (React для построения интерфейса, Redux для круговорота данных).
Немного философии
Все нативно, поэтому забудьте про полную кроссплатформенность. Платформы разные, поэтому и компоненты разные. У них разная логика и механика взаимодействия. Можно писать все на JS и выкинуть понятие native, но вы этого не хотите. Native — это ваше преимущество!
На примере приложения Vine в iOS. Что принято делать в iOS? Внизу TabBar, в нем принято переключать экраны: главная, профиль, поиск. Сверху NavigationBar, и в нем принято писать название и кнопки слева-справа (слева обычно back стоит, а справа — какое-нибудь действие). А в Android все не так. Есть тоже NavigationBar, но он другой, в нем не принято кнопки делать. Для этого есть отдельный компонент, называется ToolBar-ом. В Android-е принято делать SegmentedActivity — она сверху, очень похожа на iOS TabBar, но механика работы у него абсолютно другая. Если в TabBar-е мы не можем свайпом переключать экраны, то в Android-е это можно делать, и это принято делать, и именно так оно и работает.
Кроссплатформенность
- интерактивные компоненты (навигация, меню, ...) будут разные
- из-за этого раскладка приложения может быть разной
- логические компоненты приложения будут одинаковые, и в это главная прелесть
Из чего состоит приложение?
- нет привычных div, span, button, input и т.п.
- нет привычного CSS
- нет DOM
Компоненты
Приложение строится из компонент платформы — это нативные модули, завернутые в React-компоненты
- есть кроссплатформенные: View, Text, Image, Picker, ...
- есть специфичные для iOS: TabBarIOS, ActionSheetIOS, ...
- есть специфичные для Android: BackAndroid, ToolbarAndroid, ...
[Вот так это выглядит, реальный код]
Интересно, что кнопок нет! Для вас любая кнопка — это просто стилизованная область, у которой есть обработчик нажатия. Никакой механики кнопки нет. И поэтому в React-е есть вот эти touchable-элементы, вы оборачиваете всё, что угодно и у вас всё что угодно становится кнопкой по сути (есть обработчик onPress). Scroll-ы — отдельный компонент. Это сегментированный вид. Он рендерит только то, что находится на экране, и с ним нужно работать чуть по другому. Потому ScrollView тут тоже отдельный. Отдельная механика, если используется клавиатура. Потому отдельное свойство есть — чего с ним делать. Отдельно свойство refreshControl. Если кто-то знает, как разрабатывать на iOS, то это очень похоже.
[Вот как выглядит текстовое поле]
Какие-то свойства совпадают с привычным HTML-input-ом, а другие — нет.
CSS не настоящий — это полифил
- верстка абсолютными значениями, никаких относительных величин
- для раскладки есть ограниченная реализация flexbox-свойств
- полной поддержки CSSx никогда не будет, она не нужна
- всего реализовано около 70-ти свойств, на самом деле их хватает; на всякий случай всегда есть SVG.
[Пример CSS #1]
Компонент PixelRatio преобразует значения из density points в настоящие пиксели для разных экранов (Retina и прочее).
[Пример CSS #2]
Вот это пример с flex-ом. Хватает минимального набора, чтобы верстать.
Болванка приложения
- подключайте redux, без него будет совсем плохо
- продумайте свои экраны и логику переходов
- будут различия для iOS и Android
- главным компонентом будет Navigator
[Пример кода приложения]
Navigator
Имеет ряд проблем:
- императивное API (методы) для управления
- надо сразу продумать взаимодействие с Navigator
- анимации и жесты сложно управляемы
- NavigatorBar совсем отвязан от общей жизни
- после разработки нескольких экранов вы начнете испытывать боль
Во многом, проблемы решаются с помощью redux.
[Почему это плохо?]
Чтобы запушить какой-нибудь роут, или сделать back (перемотать на другой экран) — надо сделать ссылку на Navigator, а потом эту ссылку получить. Причем изначально её не будет, т.к. Navigator-а еще нету.
[Интерфейс выглядит, как связанные компоненты]
[А на самом деле всё выглядит вот так]
NavigationBar или зачем нужен redux
- не стоит пытаться связывать MyComponent и NavigationBar
- лучше использовать global state и dispatch actions (flux/redux)
В декабре 2015 Eric Vicenti организовал проект navigation-rfc, с помощью сообщества, попытался решить проблемы Navigator. В феврале 2016 проект переехал в мастер React Native под название NavigationExperimental и теперь развивается силами Facebook. А старый Navigation больше не будет поддерживаться.
NavigationExperimental — что сделано
- состояние управляется через reducer
- вместо императивного API — action dispatcher
- логика навигации отделяется от представления
- разделение NavigationBar, анимаций и жестов управления на различные компоненты
[Пример кода навигации]
Анимации
- реализуются через специальный компонент Animated
- есть <Animated.View>, <Animated.Image>, <Animated.Text>
- работают вне React, напрямую обновляя нативные компоненты
[Пример кода анимации]
Работает очень плавно, можно комбинировать последовательно/параллельно, и делать довольно безумные штуки.
Нативные модули
React Native реализует основные, но не все. Если модуля нет:
- поискать компонент в UIExplorer (демо-приложение React Native)
- найти правильное название модуля в терминах OS
- поискать в исходных текстах, возможно он недокументирован (как фотку сделать, SVG)
- js.coach/react-native — плагины для React Native
- отдавайте предпочтение нативной реализации, а не JS
Как подключить нативные модули
Используйте rnpm — React Native package manager:
$ rnpm link react-native react-native-google-analytics-bridge
Кроссплатформенность компонент
Неправильный путь — разложить все по папкам:
- common/components
- android/components
- ios/components
и подключать их в зависимости от платформы
Правильный путь — разложить все по папкам:
- MyComponent/Component.ios.js, MyComponent/Component.android.js
- ComponentIOS, ComponentAndroid
Для платформо-зависимых компонент (ComponentIOS, ComponentAndroid) удобно класть рядом пустышку, и не испытывать проблем, что какой-то компонент не найден на платформе.
Как написать нативный компонент
- не надо писать все на JS
- у компонента должна быть реализация в UIKit или Android API
- если ее нет, то вы хотите странного, скорее всего
Финал доклада, видео с этого места.
PS
Коллега скинул ссылочку на Weex — две недели назад Alibaba передал проект Apache.
И опять внутри Vue. Что-то оно все время путается у меня под ногами.
Только проникся идеями React+Redux, бегаю с ними, как сумасшедший с бензопилой, в попытках везде применить. А тут что получается — разворачивай дебаркадер?!
Будет очень интересно почитать сравнение, может кто возьмется — тема на Хабре новая.