Drive your career as React Developer with Symphony Solutions!
×Закрыть

Как сделать мобильное приложение с помощью JS. Путь React Native

Привет! Я работаю с Front-end уже 4 года, люблю JavaScript и современный рэп. Если вам это кажется странным, то, пожалуйста, не читайте дальше.

Свою карьеру в IT я начал с PHP и верстки, потом мне на пути повстречалась поддержка серверов на nginx и Apache, работа с SQL-базами данных, Yii 2 и Symfony. Затем увидел jQuery и мне показалось, что это магия (в этом месте фронтенд-разработчики должны надорвать животики). С того момента начал больше времени уделять фронтенду и со временем решил стать JS-разработчиком. Сейчас я умею в ReactJS, Redux, React Native (как вы поняли), имел опыт с монструозной CMS на Java и лидингом других разработчиков. Именно во время работы в AB Soft я максимально погрузился в мир Front-end и JS.

Если вы хотите связать свою жизнь с разработкой приложений, то лучше обратиться к Swift, Kotlin, Objective-C, Java. В общем, к чему-то более нативному. Ну и выбрать приоритетную для себя платформу для разработки (потому что дешевле будет писать для того же Android). Но! Если вы уже и так плывете по IT-миру на волне JS и его хайповых фреймворков, то велкам! Почему бы не попробовать React Native?

Дисклеймер. Спешу расстроить: Snapchat вы на нем не напишете :)

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

В то же время у вас есть в npm куча библиотек, которые могут помочь в решении разных задач (но не всех, об этом чуть позже). Также на GitHub есть много библиотек, реализующих компоненты, функции, UI, роутинг, и не только для вашего приложения. А еще здесь довольно живое комьюнити. Так что все это может значительно облегчить разработку.

Самый легкий путь — юзать Expo

Expo — это фреймворк (фреймворк для фреймворка, прикинь о_0) и платформа, которая во многом облегчает жизнь начинающему разработчику или разработчице на React Native:

  1. Дает возможность разрабатывать и тестировать приложение без использования Xcode или Android SDK и их экосистем.
  2. Дает стартовый кит с готовым приложением и парой экранов. Здесь вы можете поковыряться и закрасить пробел в резюме.
  3. Имеет обширную и понятную документацию (на английском).
  4. Дает очень удобную систему тестирования своего кода и UI-приложения без необходимости создавать установочный файл. Можно даже открывать свое приложение по ссылке.
  5. Предоставляет огромное количество уже готовых инструментов и АПИ для работы с модулями устройств (акселерометр, камера, файловая система, уведомления и т. д). Полный список можно посмотреть здесь.
  6. Предоставляет свои сервера и окружение для сборки приложения и компиляции его в нативный исполняемый файл.
  7. Автоматически менеджерит ваши сертификаты и подписи Play Market и Apple Store.

Ограничения Expo:

  1. Не поддерживает много нативных библиотек (написанных на Objective-C, Swift, Kotlin и т. д.).
  2. Жестко привязан к определенной версии React Native.
  3. Ваше приложение будет иметь относительно большой размер.
  4. Если захотите отсоединить свое приложение от Expo (например, чтобы использовать парочку нативных модулей), то готовьтесь просидеть над этой задачей не один час.

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

Прежде чем начать

Необходимо иметь предустановленное ПО:

  • последнюю стабильную версию Node.js (скачать);
  • систему контроля версий Git (скачать).

Далее устанавливаем интерфейс командной строки для Expo.

npm install -g expo-cli

Если вы счастливый обладатель компьютера от Apple, то лучше установить в придачу watchman. Хотите тестировать свое приложение на физическом девайсе — установите на него приложение Expo: iOS или Android. Также можно использовать в качестве тестовой платформы эмуляторы. С их установкой разбирайтесь сами: iOS (для эмулятора iOS понадобится macOS) и Android.

«Ну давайте уже кодить!» — скажет нетерпеливый читатель, и будет прав

Напишем небольшое приложение наподобие Pinterest. В нем будет разбивка по категориям, галереи, картинки и API-коллы.

Запускаем команду expo cli для создания пустого проекта.

expo init

Далее необходимо ввести некоторые параметры для начальной настройки проекта:

При выборе шаблона начального приложения выбираем blank template. Если вы знакомы с TS, то можете применять шаблон на TypeScript. Но мы же тут собрались не для того, чтобы что-то типизировать!

Пишем название проекта и его текстовый идентификатор. Если у вас установлен Yarn, то Expo предложит использовать его вместо npm. В этой статье я буду приводить все примеры на базе npm, чтобы сделать «технологичный зоопарк» статьи минималистичным.

Дальше Expo создаст папку с проектом под тем названием, которые вы указали в slug, и сам установит необходимые зависимости. Если вы все сделали правильно, то при запуске команды npm run start у вас в консоли отобразится информация о том, что приложение сбилдилось, и появится QR-код для открытия его в приложении Expo. В браузере откроется соответствующая страница, в которой также будет консоль live reload и UI для запуска эмуляторов.

Если хотите запустить приложение сразу на эмуляторе, то можно воспользоваться командами npm run ios и npm run android соответственно.

Полный список команд можно просмотреть в ./package.json и здесь.

В симуляторе вы должны будете увидеть что-то типа этого:

Экраны

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

В нашем приложении будет 2 экрана:

  1. Главный со списком всех категорий картинок.
  2. Галерея картинок соответствующей категории.

Создаем папку Screens. В нее будем класть файлы с компонентами экранов.

Перед тем как начнем писать код для UI-компонентов, хочу рассказать вам о самом лучшем букмекере (шутка!)... о библиотеке с кросс-платформенными компонентами для RN.

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

npm install native-base

Первым будет заглавный экран CategoriesList.

Он будет выводить список категорий картинок. В реальном приложении вы будете запрашивать этот список у своего API. Мы же храним его, как и прочие утильные файлы, в папке ./data.

data/categories.js

const list = [
   {
       name: 'Architecture',
       alias: 'architecture',
       collection: 'https://firebasestorage.googleapis.com/v0/b/learn-rn-bb59c.appspot.com/o/architecture.json?alt=media&token=b5583dd0-2dbd-4cb9-a91f-76f8e7a0538a'
   },
   {
       name: 'Food',
       alias: 'food',
       collection: 'https://firebasestorage.googleapis.com/v0/b/learn-rn-bb59c.appspot.com/o/food.json?alt=media&token=8b97fcc5-b802-459a-9080-9bd3d49032a6'
   },
   {
       name: 'Abstract',
       alias: 'abstract',
       collection: 'https://firebasestorage.googleapis.com/v0/b/learn-rn-bb59c.appspot.com/o/abstract.json?alt=media&token=c7012570-af3f-4f9b-acd9-ad1a9827d837'
   },
   {
       name: 'Pets',
       alias: 'pets',
       collection: 'https://firebasestorage.googleapis.com/v0/b/learn-rn-bb59c.appspot.com/o/pets.json?alt=media&token=f866e7c7-ed4b-46e9-b7c7-ef4b2242b245'
   }
];
 
export default list;

Свойство collection — это ссылка на JSON-файл с набором картинок с сайта. Позже мы будем к нему обращаться по API и выводить эти прекрасные картинки.

screens/CategoriesList.js

import React from 'react';
import { List, ListItem, Text } from 'native-base';
import { ScrollView } from 'react-native';
import list from '../data/categories';
 
class Categorieslist extends React.Component {
   constructor(props) {
       super(props);
       this.state.categories = list;
   }
 
   state = {
       categories: []
   }
 
   render() {
       return (
           <ScrollView>
               <List>
                   {
                       this.state.categories.map((item) => {
                           return (
                               <ListItem key={item.alias}>
                                   <Text>{item.name}</Text>
                               </ListItem>
                           )
                       })
                   }
               </List>
           </ScrollView>
       );
   }
}
 
export default Categorieslist;
 

Как видите, главное отличие от React’а, на первый взгляд, заключается в тегах jsx. Здесь мы не используем теги HTML (из которых в большинстве случаев состоят наши реактовские компоненты). Вместо них применяем нативные компоненты, предоставленные библиотекой React Native, которые компилируются в нативные представления платформ.

Несколько слов о готовых компонентах, которые мы использовали в основе UI.

<ScrollView /> — контейнер для отображения контента, который, возможно, необходимо скроллить.

 <List /> и <ListItem /> — список и элемент списка соответственно из библиотеки Native Base. Они уже имеют стилизацию в соответствии с iOS- и Android-гайдами.

Думаю, название тега <Text /> говорит само за себя.

Список категорий

Чтобы насладиться результатом своей кропотливой работы, убираем все лишнее из App.js и импортируем туда свой экран:

import React from 'react';
import CategoriesList from './screens/CategoriesList';
 
export default function App() {
 return (
     <CategoriesList />
 );
}

Если вы не выключали команду npm run, то уже можете лицезреть результат на экране эмулятора. Выключали? Тогда запустите еще раз: npm run ios или npm run android.

Если вы установили на свой девайс Expo client и хотите открыть приложение в нем, просто отсканируйте QR-код из терминала. На экране вы должны увидеть это:

У вас все так и выглядит? Я вас поздравляю! А если нет, то просто сравните свой код с тем, который написан в статье.

Делаем сетку картинок

У Pinterest очень интересная сетка с картинками. Ее аналог в простонародье известен под названием Masonry. Добрые люди уже запилили его в виде npm-пакета. Но пока мы с ним заморачиваться не будем, лучше погрузимся в работу и стилизацию нативных компонентов и компонентов NativeBase.

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

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

components/ImageGrid.js

import React from 'react';
import {Card, CardItem} from 'native-base';
import {View, ScrollView, StyleSheet, Dimensions, Image} from 'react-native';
 
/**
* Получаем объект экрана через API RN
* чтобы в дальнейшем использовать для расчетов ширину
*/
const window = Dimensions.get('window');
const imagesWidth = window.width - 20;
 
export default class ImageGrid extends React.Component {
   render() {
       const { list } = this.props;
 
       return (
           <ScrollView>
               {list.map((item) => {
                   const imageRatio = imagesWidth/item.width;
 
                   return(
                       <View key={item.url} style={styles.cardWrapper}>
                           <Card style={styles.card}>
                               <CardItem style={styles.cardItem}>
                                   <Image source={{uri: item.url}}
                                       style={{
                                           ...styles.image,
                                           height: item.height * imageRatio
                                       }}
                                   />
                               </CardItem>
                           </Card>
                       </View>
                   );
               })}
           </ScrollView>
       );
   }
}
 
const styles = StyleSheet.create({
   cardWrapper: {
       borderRadius: 20,
       marginBottom: 10
   },
   card: {
       borderRadius: 20,
       marginLeft: 10,
       marginRight: 10
   },
   cardItem: {
       paddingLeft: 0,
       paddingRight: 0,
       paddingTop: 0,
       paddingBottom: 0
   },
   image: {
       height: 300,
       width: '100%',
       borderRadius: 20,
       width: imagesWidth
   }
});

Стилизация

Из react-native мы здесь импортируем StyleSheet. Это класс, который обеспечивает доступ к абстракции стилизации (как CSS). С помощью метода Create создаем объект, содержащий ссылки на конкретные наборы стилей. Имена ссылок соответствуют названиям свойств объекта. Сами же стили присваиваем компоненту с помощью пропса style. Также мы можем передавать в style просто объект.

<Text style={{color: #ccc}}>Some text</Text>

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

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

Также вы наверняка обратили внимание на компоненты Card и CardItem. Это компоненты из библиотеки NativeBase, которые мы берем для того, чтобы не заморачиваться со стилизацией и позиционированием элементов картинок. Также в этих компонентах можно размещать множество разных наборов контента: текст, заголовки, кнопки, фоновые изображения и т. д. За подробностями идите в доку. В CardItem мы передаем параметр button={true}, что позволит карточке вести себя как кнопка.

Картинки

Теперь необходимо отдельно упомянуть компонент Image. Он стилизуется так же, как и остальные компоненты, имеет обязательный параметр source, с помощью которого указываем путь картинки, которую хотим вывести. Есть два способа это сделать:

  1. В source прокидывать require (‘image/path.png’) для локальных картинок. Однако если вы попытаетесь динамически генерировать строку внутри require, у вас ничего не получится: RN будет в этом месте ломаться.
  2. Указывать объект типа {uri: ‘https://remote.image/path.png’}. В этом случае вы указываете URL удаленной картинки, которую ваше приложение должно будет подгрузить. Также в uri можно передавать строку формата base64, однако если у вас там большая строка, то на этапе компиляции сервер Expo может просто отказаться компилировать ваше приложение, сославшись на слишком большой размер js-файла.

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

Навигация

Для реализации навигации между экранами воспользуемся пакетом react-navigation.

npm install react-navigation

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

expo install react-native-gesture-handler react-native-reanimated react-native-screens react-native-safe-area-context @react-native-community/masked-view
npm install react-navigation-stack

Нужно отметить, что навигация в приложениях организована иначе, чем в браузерах. В приложении можно хранить историю всего роутинга вместе с параметрами и даже частично состояние приложения. Сами элементы истории организованы по принципу стека. Переходя на новый экран, пользователь как бы кладет его (экран) поверх стека. Кнопка «Назад», которая есть в интерфейсе как iOS, так и Android, удаляет элемент стека.

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

  1. Screen — компонент экрана для роута;
  2. navigationOptions — настройки навигатора, в которых можно указать заголовок, название для кнопки «Назад» и прочие настройки. Также в качестве этого свойства можно указывать callback, который принимает параметры из навигатора, динамически формирует и возвращает нужные нам значения (этим мы будем активно пользоваться).

Вторым параметром он принимает объект со значениями для настройки навигации. Пока мы воспользуемся им для указания экрана по умолчанию с помощью свойства initialRouteName.

Вообще единственным обязательным значением для элемента коллекции является свойство screen.

./navigation.js

import { createStackNavigator } from 'react-navigation-stack';
import { createAppContainer } from 'react-navigation';
 
import CategoriesList from './screens/CategoriesList';
import GridScreen from './screens/GridScreen';
 
const Stack = createStackNavigator({
   MainList: {
       screen: CategoriesList,
       navigationOptions: {
           title: 'Photo Categories'
       }
   },
   ImagesGrid: {
       screen: GridScreen,
       navigationOptions: ({ navigation }) => {
           return {
               title: navigation.state.params.title
           };
       }
   }
},
{
   initialRouteName: 'MainList'
});
 
export default createAppContainer(Stack);

В нашем приложении будет всего два экрана: общий список и экран для вывода контента выбранной коллекции.

Роут MainList будет вызывать компонент CategoriesList, а с помощью navigationOptions мы укажем заголовок для экрана. Роут ImagesGrid будет, в свою очередь, вызывать компонент экрана GridScreen.

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

createStackNavigator возвращает компонент. Но мы не можем просто взять и использовать его в приложении. Для этого необходим createAppContainer, который связывает все, что мы можем сотворить с помощью реакт-навигации, с нативными API платформ. createAppContainer возвращает компонент, который будем использовать как корневой в своем проекте. Для этого немного изменим файл App.js.

./App.js

import React from 'react';
import Navigator from './navigation';
 
export default function App() {
 return (
     <Navigator/>
 );
}

Внедряем навигацию в компоненты.

./screens/CategoriesList.js

import React from 'react';
import { List, ListItem, Text } from 'native-base';
import { ScrollView } from 'react-native';
import categories from '../data/categories';
 
class CategoriesList extends React.Component {
   constructor(props) {
       super(props);
       this.state.categories = categories;
   }
 
   state = {
       categories: []
   };
 
   render() {
       const { navigation: { navigate } } = this.props;
 
       return (
           <ScrollView>
               <List>
                   {
                       categories.map((item) => {
 
                           const { collection, alias, name } = item;
 
                           return (
                               <ListItem
                                   key={alias}
                                   onPress={() => navigate('ImagesGrid', { collection, title: name })}
                               >
                                   <Text>{name}</Text>
                               </ListItem>
                           )
                       })
                   }
               </List>
           </ScrollView>
       );
   }
}
 
export default CategoriesList;

На экран с перечнем категорий теперь нужно добавить какой-нибудь способ для навигации между нашими экранами.

Когда мы в файле navigation.js передали в качестве аргумента экран CategoriesList, то создали вокруг него HOC (компонент высшего порядка), который в пропсы этого компонента передал некоторые данные и методы для реализации навигации. Нас интересует в первую очередь метод navigation.navigate(). Как вы уже поняли по его названию, он осуществляет навигацию между разными экранами; какой именно экран нужно использовать, определяем в первом аргументе. Название экрана совпадает с названиями объектов в коллекции, которую мы передавали в createStackNavigator (navigation.js); вторым параметром можем передать объект с дополнительными данными, которые будут передаваться в createStackNavigator и на следующий открытый экран. Сейчас с помощью второго аргумента мы передаем идентификатор коллекции (collection) и заголовок экрана (title).

А теперь давайте создадим экран просмотра коллекции, в котором будет реализована логика навигации и загрузки изображений.

Дисклеймер. Я знаю, что с точки зрения современного модного молодежного фронтенда, в котором в основном используется redux и какая-нибудь saga для манипуляций с состоянием приложения, обращения к АПИ находятся в коде подальше от представлений. Поэтому если вы вдруг решили создавать серьезное приложение, то лучше отнестись к его архитектуре максимально серьезно (насколько вообще можно говорить о серьезности в контексте приложения на JS :). Прочитайте об однонаправленном потоке данных, Flux, Redux и прочем.

./screens/GridScreen.js

import React from 'react';
import { ActivityIndicator, StyleSheet, View } from 'react-native';
import ImageGrid from '../components/ImageGrid';
 
export default class GridScreen extends React.Component {
 
   state = {
       isLoaded: false,
       imagesList: []
   }
 
   async componentDidMount() {
       /**
        * navigation - прокидвывает react-navigation в пропсы.
        * В navigation.state.params находятся наши дополнительные данные,
        * которые мы передавали в главном экране
        */
       const { navigation } = this.props;
 
       try {
           const response = await fetch(
               navigation.state.params.collection,
               { method: 'GET', redirect: 'follow'}
           );
           const data = await response.json();
           this.setState({
               imagesList: data,
               isLoaded: true
           });
       } catch (e) {
           console.log(e);
       }
   }
 
   render() {
       if (!this.state.isLoaded) {
           return (
               <View style={styles.loaderContainer}>
                   <ActivityIndicator size="small" style={styles.loader} />
               </View>
           );
       }
 
       return (<ImageGrid list={this.state.imagesList}/>);
   }
}
 
const styles = StyleSheet.create({
   loader: {
       flex: 1,
       justifyContent: "center",
       alignItems: "center"
   },
   loaderContainer: {
       flex: 1
   }
});

Немного выше в экране CategoriesList мы передавли через метод navigate параметр collection. Теперь в этом экране мы достаем его из props. Collection является урлом для получения массива в json. Его мы будем парсить, получать картинки и выводить их на экран.

Метод componentDidMount у нас асинхронный. В нем мы будем подгружать json с информацией и ссылками на картинки, обрабатывать его и уже на основе данных в нем выводить контент. Тут для людей, которые работают с реактом, ничего нового нет, но на всякий случай поясню. Когда только открывается экран и мы еще не запросили данные по API, у нашего приложения состояние загрузки state.isLoading = true. В этом случае компонент выводит спинер загрузки (он же нативный компонент ActivityIndicator). Когда же загрузка заканчивается, мы обновляем state распарсенным массивом картинок и свойством isLoaded = false, компонент перерисовывается, но на этот раз у него уже есть массив, который можно передать в компонент ImageGrid, чтобы он отрисовал нам картинки. Обратите внимание на стили loader и loaderContainer — да, в RN есть всеми нами любимый flex. Такая комбинация стилизаций дает возможность отображать объекты строго посередине экрана.

Если вы все сделали правильно, то после запуска npm run ios или npm run android в эмуляторе вы должны увидеть что-то похожее на это:

Метод componentDidMount у нас асинхронный. В нем мы будем подгружать json с информацией и ссылками на картинки.

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

На этом абзаце, скорее всего, 50% читателей закрыли статью и пошли дописывать резюме (еще 40% сделали это наверняка раньше), но мне еще есть что вам сказать.

Дебагинг

Наверняка вы заметили, что в консоли приложение показывает различный вывод. Мы можем пользоваться привычным console.log() для вывода там значений переменных.

Помимо этого, Expo предоставляет мощную (как сын маминой подруги) утилиту для дебагинга в тестовом режиме. На mac в эмуляторе нужно нажать сочетание клавиш Command + D. Откроется окно, в котором нужно нажать Toggle Element Inspector.

Перейдем в режим дебага, который функционально похож на инспектор в Chrome: там можно просмотреть структуру компонентов и примененные к ним стили, подсветить touchable-элементы и т. д.

Используйте нижнюю панель для переключения между режимами инспектора. Чтобы закрыть его, нажмите сочетание клавиш Command + D и снова — Toggle Element Inspector.

Компиляция в установочный файл

Затронем тему компиляции в установочный файл и подготовку к релизу на платформы App Store и Google Play. Для начала нужно будет подготовить конфигурационный файл app.json. В нем надо указать данные для релиза: ID бандла, ссылку на иконку приложения, версию и прочее. После этого нужно будет лишь запустить команду Expo для билда expo build:android или expo build:ios, в процессе он запросит у вас необходимую для компиляции информацию. В случае с приложениями для iOS Expo предлагает заменеджерить сертификаты и электронные подписи, которые используются в процессе дистрибуции, что довольно удобно (думаю, не надо бояться, что разработчики Expo украдут ваши креды (лично я побаивался!)).

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

Ура, это все!

Ты дочитал до конца, а значит ты — молодец. Поэтому вот тебе ссылка на GitHub с проектом, который мы рожали всю эту статью.

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

В общем, как-то так. Жду ваших вопросов, проклятий и шуток в комментариях. Кому интересен процесс релиза в Apple Store, тоже пишите: если желающих будет много, превозмогу себя и расскажу о подготовке к релизу.

LinkedIn

36 комментариев

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

C нуля не «завелось». Но с репозитория, с апгрейдом expo — успешно. Спасибо за проект для «пощупать».

Довелось разрабатывать на RN и Ionic(3) изучая параллельно — могу сказать что обе платформы немного сыроваты и часто попадаешь на нелогичные вещи, баги. По субъективным ощущениям RN тормозит на Android, собирается в APK, по размерам превосходящую установочный пакет IOS раза в 3.

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

RN — это больше про конструктор, но даже добавить launchscreen было проблемой на IOS, формы — нет готового решения, TS и SCSS — сам добавляй. Меню — выбери из 3-4 штук, половина из которых работает коряво (к примеру — YouTube плеер не дружит с одним из меню), expo — не воспользуешься, так как нужных плагинов нет. Дебажить с телефона то еще дно.

Думаю, что Flutter будет крутой заменой обоим, открывал на телефоне приложения из Play Store написанные на нем — в восторге от скорости работы.

дебаггінг — тяжко там
деякі версії не заводились в продакшені
залежність від конкретної версії — це дійсно біч
деякі дуже популярні ліби не підтримуються
firebase dynamic linking — тільки продакшен, на деві треба обходити — тому тестування БІЛЬ
про кешування картинок описали тільки в останніх версіях, в списках там трабли для иос чи андроїда, не пам"ятаю

додали веб тільки нещодавно, деякі базові компоненти не існують одночасно — тому треба писати прослойку (а останній динамічний імпорт я так і не налагодив — не вистачило часу)

rem не підтримується з коробки — тобто не можна написати в стилях 1rem..., але рішення є

netinfo — якась шляпа

async в об"яві рендер функцій — шляпа (можливо це вимоги реакту), витатили багато часу на це

досить часто відслідити де саме проблема тяжко по трейсу

щоб зрозуміти що діється — останній реліз blog.expo.io/...​ow-available-b91897b437fe

Проблеми
github.com/...​q=is:issue is:open sdk 36

Щоб ви розуміли до 35ї версії були великі проблеми з ios — стораджем...

Перспективи є, але треба ще час

мені все ж подобається ionic

Спасибо за подробный ответ!

додали веб тільки нещодавно

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

async в об"яві рендер функцій — шляпа (можливо це вимоги реакту), витатили багато часу на це

Рендер в реакте не может быть асинхронным, если вы об этом. Но это и не проблема, можно при маунте компонента инициировать нужные запросы, показать пользователю спиннер пока они идут

Окромя «О, майн гот!» ничего сказать не могу. Это же каким нужно быть «JSником» ... ну да ладно... если нужно что-то сварганить на коленке и продать заказчику это «что-то»... то да RN — лучший вариант. Хотя, я бы предпочел в этом случае Flutter, что собственно и делаю .... в нем по крайней мере понятная структура и он так дико не тормозит....
Хотелось бы еще похейтить .... но столько экзальтированых веников, страшно что толпой сметут :)

предпочел в этом случае Flutter, что собственно и делаю .... в нем по крайней мере понятная структура и он так дико не тормозит

RN действительно заметнее тормознутее Flutter?

Не хейтер, интересуют именно реальные впечатления от пробовавших и то, и другое. От своих коллег, писавших на RN, каких-то особых «фе» в сторону этой платформы, кроме нестабильности тулчейна, не слышал...

RN норм тема) По началу именно так кажется когда ты весь такой из себя реакт дев на изиче начинаешь делать мобильные апки. Но когда начинается продакшен, который не пет проект где ты можешь сделать как попроще, а по-настоящему, где заказчик как нарисует... А ещё ж нужно чтобы все выглядело одинаково и на иОс и на Андроиде... В общем улыбка понемногу сходит с лица.

После РН Флаттер кажется какой-то космической технологией инопланетян. Конечно повозившись и у него находятся косяки да неудобства, но обратно возвращаться не хочется ни разу.

Кстати, фе про РН можно не услышать по двум причинам — недостаточно прод опыта или не щупали альтернативы(я конечно о флаттре)

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

я вот хочу ручками поСЧупать исходники флаттера... все ни как не дотянусь... мне кажется, что ничего интересного кроме очередной «обертки» вокруг GTK/QT не найду...

Там нет под капотом ни GTK, ни Qt. Библиотека отрисовки Skia есть, да — но она и в «штатном» Андроиде используется.

Заглянул, любопытно... очень...
Спасибо.

А ты не хейти, просто расскажи как во Флаттер-стане круто)

такое же Г.... нейтив — рулит :) а все это «пишем на все платфмы сразу» — отличный способ разводить лохов :) и сегментировать рынок...

А ещё хейтер может написать?)

Болше ничего, это как ездить на «все сезонной резине» там где есть и зима и лето ... вроде все ездит, но как-то стремно ...

Haters gonna hate. Вот только в реальности всё больше мобильных приложений, особенно в бизнес- и корпоративных сегментах, делают на кросс-платформенных фреймворках.

Уже писал когда-то ранее в одном из похожих обсуждений — подобный хэйт настолько же бессмысленен, как и хэйт на тему того, почему не все десктопные приложения пишутся на C++. Ответ ровно тот же самый — с развитием Rapid Application Development инструментария дороговизна и сложность разработки на «плюсах» очень и очень редко оправдывает всю ту мощь и гибкость, которые разработчик получает в своё распоряжение. Мобильная разработка придёт — если ещё не пришла — ровно к тому же самому: нативный код будет использоваться очень точечно для задач, где по-другому никак, и подключаться к основному кросс-платформенному «скелету» в виде плагинов.

У Flutter здесь, кстати, весомый козырь — если для приложения допустИм свой собственный «фирменный» стиль, то одинаково на iOS и Android оно будет выглядеть без особых дополнительных усилий разработчика. Ну а, поскольку, всё больше приложений используют уникальный дизайн, а не следуют 1-в-1 предписанным разработчиками ОС UI гайдлайнам, то здесь Flutter действительно даст фору RN, использующему «под капотом» родные UI компоненты мобильной ОС.

Возможно, мое мнение базируется на собственной практике, где, по-большей части, приходиться работать с «железной» основой... так что моя колокольня такова и я с нее смотрю :)

Для плотной работы с «железом» (Bluetooth, audio, GPU и т.п.) без native разработки не обойтись — с этим никто и не спорит. Вопрос, скорее в том, какую часть приложения составляет функционал для плотной работы с «железом», а какую — взаимодействие с пользователем.

Если UI примитивный, но много работы с чипсетом смартфона на низком уровне — нет смысла тащить в такой проект RN / Flutter.

Если же, наоборот, плотная работа с железом — это, от силы, 20% приложения, то имеет смысл обернуть её в нативный плагин и использовать из основной части, написанной на кросс-платформенном фреймворке.

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

Костя, спасибо! Лучший)

если нужно, что-то большее чем работа с екранами, что-то загрузить и показать, и провести простенькую работу с инпутами, готовьтесь к тому, что експо не ваш вариант как и реакт-нейтив.
У меня приложение на 5-6 екранов заняло 45 Мб

У меня в приложении больше 100 экранов и оно весит меньше 60 мб. Функционал далеко не загрузить, показать.
RN наверное не вариант если нужно сделать нормальную интеграцию рекламы в апку, или работать с датчиками типа bluetooth, или для разработки игр.

Не есть много кейсов которые RN закрывает.

Статья ознакомительная и в ней много неточностей например

Вместо них применяем нативные компоненты, предоставленные библиотекой React Native, которые компилируются в нативные представления платформ.

JS ни во что не компилируется.

про 100 экранов и 60 Мб — вы меня успокоили
На счет рекламы — blog.expo.io/...​-expo-project-aa4e48ac848
на бумаге выглядит супер просто. Как раз начну заниматься этим, если не забуду, отпишусь о результатах.
ПС. Если тебе читатель интересен результат, пингани меня через месяц другой.

Рекламу супер-просто интегрировать. AdMob используется практически всеми и хорошо интегрирован в expo. Могу поделиться исходниками, если надо будет.

JS ни во что не компилируется.

JS — да, но автор говорит о разметке экранов. Слово «компилируется» тут неточное, скорее, речь о том, что разметка средствами движка React Native (yoga, по-моему) превращается в нативные view мобильной OS.

Это не совсем так, yoga отвечает только за разметку, то как нативные элементы расположены относительно друг друга на экране(что бы мы могли писать разметку одинаково на iOS и Android yogalayout.com). Точно так же как в вебе div из jsx никак не превращается в div в DOM-дереве, а лишь является частью react-dom на основе которого строится реальный дом. Точно так же view это часть shadow-tree на основе которого для iOS отрендерится вполне себе нативный UIView. Не происходит никакой магии и никаких преобразований JS в нативные компоненты. Да все немного сложнее чем я написал и за View из RN стоит намного более сложная идея, но это уже другая история и повод почитать исходники RN.

Спасибо! в следующий раз исправлю)

Но кстати про рекламу не соглашусь — довлоьно просто через API Expo интегрировать все возможные баннеры и виды рекламы AdMob.

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

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

є реальний великий апп, яким користувався sun на expo і все більш-менш ок
головне руки і голова

Привет! Я работаю с Front-end уже 4 года, люблю JavaScript и современный рэп. Если вам это кажется странным, то, пожалуйста, не читайте дальше.

 ок, уговорил

Подписаться на комментарии