Перетяжка, Премия ТПрогер, 13.11
Перетяжка, Премия ТПрогер, 13.11
Перетяжка, Премия ТПрогер, 13.11

Как разработать своё первое приложение на React Native

Аватар Типичный программист
Отредактировано

Разбираемся, что же такое React Native, почему он сейчас важен и популярен, а также создаём небольшой проект для демонстрации основ.

68К открытий73К показов

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

Что такое React Native?

Сначала нужно разобраться, что есть React. React — это инструмент для создания пользовательских интерфейсов. Его основная задача — обеспечить отображение на экране того, что можно увидеть на веб-страницах. React позволяет легко создавать интерфейсы, разделяя каждую страницу на небольшие фрагменты и компоненты. Он очень удобен для создания веб-приложений и не требует большого порога вхождения. Так вот, разработчики популярной соцсети подумали, что было бы круто, если бы React можно было бы использовать для создания кросс-платформенных мобильных приложений, и в 2015 году React Native был представлен публике и появился на GitHub, где уже каждый мог внести свой вклад. React популярен по нескольким причинам. Он компактен и отличается высокой производительностью, в особенности при работе с быстро меняющимися данными. За счет своей компонентной структуры, React поощряет вас писать модульный и многократно используемый код.

В мире кроссплатформенной мобильной разработки уже были свои решения, к примеру Apache Cordova — технология, которая позволяла использовать HTML + CSS + JavaScript + нативный функционал платформы, на которой приложение было запущено, для его работы. Однако, технология имеет большую проблему — быстродействие. Так же на данный момент существуют и другие, такие как Xamarin, Flutter, QT и так далее.

В React Native код пишется на JavaScript, и исполняется при помощи JavaScriptCore — движка, который использует Safari. Так же можно использовать нативные модули платформы, к примеру камеру или Bluetooth. Для этого пишется код, реализующий функциональность на языке, который предназначается для разработки под конкретную платформу (Java/Swift/Objective C) и сообщается со средой JavaScript посредством bridge.

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

Для большинства стандартных элементов UI есть компоненты в RN, к примеру View = UIView в iOS, так что реализовывать изыски интерфейса должно быть несложно, если есть знания React.

Почему же RN стал таким популярным?

  • для написания кода используется JavaScript, в частности React;
  • есть возможность быстро написать приложение под обе платформы. Меньше затраты — выгоднее бизнесу;
  • большая библиотека нативных и не-нативных компонентов;
  • для отладки можно использовать браузер, так же есть hot-reload для быстрого просмотра изменений. Нет необходимости пересобирать приложение при внесении изменений в код;
  • для отрисовки компонентов используются нативные компоненты используемой системы (например UIImage/ImageView), соответственно производительность такого UI выше, чем при использовании webview;
  • просто написать свою библиотеку для RN, использующую нативный функционал системы;
  • ещё одна причиной почему RN набрал популярность в последние годы является то, что его используют такие гиганты как Skype, Tesla, Baidu, Bloomberg и т. д.

Первое приложение

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

Нам понадобится cli утилита npx, которая поставляется вместе с Node.js, Android Studio — если мы хотим протестировать приложение на Android, либо Xcode — если на iPhone. Как установить указанные инструменты подробнее можно почитать здесь.

Начнем с того, что создадим проект командой npx react-native init RandomGuysApp. В RN приложение также можно добавить TypeScript, но мы этого здесь делать не будем.

Спустя какое-то время у нас создалась такая структура папок

Как разработать своё первое приложение на React Native 1

В консоли пишем yarn add @react-navigation/native @react-navigation/stack react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view. Это установит библиотеку для навигации, что-бы можно было переходить между экранами приложения и зависимости для неё. Redux, или другую библиотеку для управления состоянием я решил не подключать, так-как думаю, что в нашем примере это будет немного излишне. После установки, если вы собираетесь запускать приложение на iOS, нужно зайти в папку ios и написать pod install (предварительно установив cocoapods на компьютер).

В index.js написано:

AppRegistry.registerComponent(appName, () => App);

это показывает, что компонент App является точкой входа в наше приложение. Я предпочитаю хранить код в отдельной папке, поэтому перенесу App.js в новую папку — src, сменив в index.js путь до него на

import {App} from './src/App';

Как разработать своё первое приложение на React Native 2

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

Создадим папку navigators, а в ней RootNavigator.js, в который поместим такой код

			import * as React from 'react';
import {createStackNavigator} from '@react-navigation/stack';
import {PersonListScreen} from '../screens/PersonListScreen';

const Stack = createStackNavigator();

export const RootNavigator = () => {
	return (
	<Stack.Navigator initialRouteName={'list'}>
		<Stack.Screen name={'list'} component={PersonListScreen} />
	</Stack.Navigator>
	);
};
		

Пара моментов:

  • компонента ListScreen еще не существует;
  • в приложении ожидается всего два экрана, так что структурно оно несколько упрощено, для демонстрации работы с RN.

Что здесь происходит? Создаётся новый стек навигации, в котором указывается список экранов, находящихся в нем. А также указывается стартовый экран стека. Т. к. у нас будет всего один стек, то по сути это и будет стартовый экран приложения.

Перейдем к созданию первого экрана. Добавим папку screens, в которой создадим файл PersonListScreen

Как разработать своё первое приложение на React Native 3

Там разместим такой код:

			import React, {Component} from 'react';
import {FlatList, View, StyleSheet} from 'react-native';
import {PersonListItem} from '../components/PersonListItem';

export class PersonListScreen extends Component {
	state = {
		list: [],
		isLoading: false,
	};

	componentDidMount = () => {
		this.onRefresh();
	};

	getMoreData = (isRefreshing) => {};

	onRefresh = () => {
		this.getMoreData(true);
	};

	onScrollToEnd = ({distanceFromEnd}) => {
		if (distanceFromEnd < 0) {
			return;
		}
		this.getMoreData(false);
	};

	onItemPress = (item) => {
		this.props.navigation.navigate('info', {person: item});
	};

	keyExtractor = (person) => person.login.uuid;

	renderItem = ({item}) => {
	return (
		<PersonListItem
			person={item}
			onPress={this.onItemPress.bind(this, item)}
		/>
		);
	};

	render = () => {
	const {isLoading, list} = this.state;

	return (
		<View style={styles.container}>
		<FlatList
			data={list}
			renderItem={this.renderItem}
			keyExtractor={this.keyExtractor}
			refreshing={isLoading}
			onRefresh={this.onRefresh}
			onEndReached={this.onScrollToEnd}
			onEndReachedThreshold={0.2}
		/>
		</View>
	);
	};
}
		

Опять же, PersonListItem еще не существует, но это временно. FlatList, это эффективный компонент для рендера списков — он поддерживает PullToRefresh, прокрутку к элементу списка по индексу, производительный рендер за счет отключения рендера компонентов, которые слишком далеко от видимой области экрана и многое другое. Конечно, одинаковые элементы в столбик/ряд можно рисовать и другим образом, например через ScrollView, но это самый эффективный способ.

В renderItem передается каждый элемент массива из пропсы data, и возвращается списковый компонент. keyExtractor это по сути аналог свойства key, только в виде функции, вызываемой для каждого элемента.

Итак, при заходе на страницу мы собираемся получить список юзеров, и отрисовать его. Когда список тянется вниз — обновить его, а когда мы достигаем его конца — подгрузить новые данные. Вернёмся пока к PersonListItem, добавим в components файл PersonListItem.js и заполним его таким кодом

			import React, {Component} from 'react';
import {StyleSheet, TouchableOpacity, Image, Text, View} from 'react-native';
export class PersonListItem extends Component {
	render = () => {
	const {onPress, person} = this.props;

	return (
		<TouchableOpacity style={styles.container} onPress={onPress}>
		<Image
			source={{uri: person.picture.medium}}
			resizeMode={'contain'}
			style={styles.avatar}
		/>
		<View style={styles.col}>
			<Text style={styles.name}>
			{person.name.first} {person.name.last}
			</Text>
			<Text style={styles.email}>{person.email}</Text>
		</View>
		</TouchableOpacity>
	);
	};
}

const styles = StyleSheet.create({
	container: {
		flexDirection: 'row',
		alignItems: 'center',
		padding: 12,
		borderBottomColor: '#b0b0b0',
		borderBottomWidth: 0.4,
	},
		avatar: {
		width: 50,
		height: 50,
		borderRadius: 25,
	},
	col: {
		marginLeft: 10,
	},
	name: {
		fontSize: 16,
		color: '#2e2e2e',
	},
	email: {
		marginTop: 10,
		fontSize: 13,
		color: '#b0b0b0',
	},
});
		

В RN нет пропсы className и стили передаются в пропсе style, а объявляются через StyleSheet.create(). Можно, конечно, использовать объект как стиль, но в этом случае не будут применяться некоторые внутренние оптимизации производительности.

Заметили, что вместо пикселей используются голые числа? Потому что по умолчанию, как единица измерения используются dp (density-independent pixels), а для конвертации в px можно использовать PixelRatio.getPixelSizeForLayoutSize(), но это нам не особо нужно. В принципе, практически все свойства стилей дублируют CSS, так-что особо проблем быть не должно. Но есть такая особенность — все компоненты в RN имеют display: flex. Ещё есть display: none, других вариантов нет. Главное отличие, что все компоненты по умолчанию имеют flexDirection: column, в отличие от браузерной версии. Есть еще несколько отличий, но перечислять я их не буду, в целом можно сказать, что в RN display: flex несколько урезанный.

Вернёмся к App.js. Заменим содержимое файла следующим кодом

			import React, {Component} from 'react';
import {SafeAreaView} from 'react-native';
import {NavigationContainer} from '@react-navigation/native';
import {RootNavigator} from './navigators/RootNavigator';

export class App extends Component {
	render = () => {
	return (
		<SafeAreaView>
		<NavigationContainer>
			<RootNavigator />
		</NavigationContainer>
		</SafeAreaView>
	);
	};
}

const styles = StyleSheet.create({
	container: {
	flex: 1,
	},
});
		

Используем наш созданный роутер, что-бы у нас работала навигация. Так же здесь используется компонент SafeAreaView, он нужен что-бы контент в iOS отрисовывался внутри «безопасных» границ экрана и, к примеру, не наезжал на «монобровь» в iPhone X.

Сборка и запуск

Попробуем собрать и запустить то, что у нас есть. Если у вас macOS, то можно использовать Xcode. Для этого при открытии проекта нужно указать файл ios/RandomGuysApp.xcworkspace внутри проекта. Если Android, то нужно установить JDK и необходимые SDK. Проще всего открыть папку android в Android Studio, и IDE установит необходимое ПО. А после этого написать в корневой папке проекта npx react-native run-android.

Когда проект запустится, то на экране должно появиться, что-то вроде этого.

Как разработать своё первое приложение на React Native 4

Это экран с названием list, который мы зарегистрировали в навигаторе. Но там пока что пусто, так как нам еще нечего отрисовывать. Поэтому вернемся в PersonListScreen.js и добавим в функцию getMoreData() код для получения данных.

			getMoreData = (isRefreshing) => {
	const limit = 15;
	const offset = isRefreshing ? 0 : this.state.list.length;
	const page = Math.ceil(offset / limit) + 1;
	fetch(`https://randomuser.me/api/?seed=foobar&results=15&page=${page}`)
	  .then((r) => r.json())
	  .then((json) => {
		this.setState({
		  list: isRefreshing
			? this.state.list.concat(json.results)
			: json.results,
		});
	  })
	  .catch((e) => {
		console.log(e);
	  });
  };
		

Для отладки приложения можно использовать react-native-debugger, либо браузер. Включается дебаггер комбинацией клавиш ctrl(cmd) + M для Android, cmd + D для iOS. Там же можно включить live reload.

Сверху к import из react-native добавим импорт модуля StyleSheet

import {FlatList, View, StyleSheet} from 'react-native';

Вниз этого же файла добавим

			const styles = StyleSheet.create({
	container: {
	  flex: 1,
	},
  });
		

и добавим этот стиль нашему View. Получаем что-то вроде такого

Как разработать своё первое приложение на React Native 5

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

			onItemPress = (item) => {
	this.props.navigation.navigate('info', {person: item});
};
		

Это переход в экран с названием info с передачей выбранного юзера как параметра. В дальнейшем его можно будет получить из компонента экрана. Теперь добавим этот экран в навигатор RootNavigator.js и напишем для него код.

			...
import {PersonInfoScreen} from '../screens/PersonInfoScreen';
...
<Stack.Screen name={'list'} component={PersonListScreen} />
<Stack.Screen name={'info'} component={PersonInfoScreen} />
...
		

Так же создадим файл src/screens/PersonInfoScreen.js и добавим туда следующий код.

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

export class PersonInfoScreen extends Component {
	renderRow = (cells) => {
	return cells.map((cell) => (
		<View style={styles.cell} key={cell.title}>
		<Text style={styles.cellTitle}>{cell.title}</Text>
		<Text style={styles.cellValue}>{cell.value}</Text>
		</View>
	));
	};

	render = () => {
	const {person} = this.props.route.params;

	return (
		<View style={styles.container}>
		<Image
			source={{uri: person.picture.large}}
			style={styles.avatar}
			resizeMode={'contain'}
		/>
		{this.renderRow([
			{title: 'login', value: person.login.username},
			{title: 'name', value: person.name.first},
			{title: 'surname', value: person.name.last},
			{title: 'email', value: person.email},
			{title: 'phone', value: person.cell},
		])}
		</View>
	);
	};
}

const styles = StyleSheet.create({
	container: {
		flex: 1,
		alignItems: 'center',
	},
	avatar: {
		width: 100,
		height: 100,
		borderRadius: 50,
		marginTop: 20,
	},
	cell: {
		marginTop: 15,
		justifyContent: 'center',
		alignItems: 'center',
	},
	cellTitle: {
		fontSize: 13,
		color: '#b0b0b0',
	},
	cellValue: {
		marginTop: 10,
		fontSize: 16,
		color: '#2e2e2e',
	},
});
		

Вот что у нас получилось.

Как разработать своё первое приложение на React Native 6

Таким образом мы сделали приложение для вывода и просмотра некоторой информации по разным людям.

Ресурсы

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

  • Официальная документация, здесь вы сможете найти описания всех API и встроенных компонентов библиотеки.
  • Один из лучших курсов для изучения React Native. Он поможет быстро разобраться в нём, а также научит пониманию экосистемы RN и React в целом.
  • Тут большой список крутых библиотек на разные случаи жизни и статей по теме.

В итоге

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

Код проекта можно найти здесь.

Следите за новыми постами
Следите за новыми постами по любимым темам
68К открытий73К показов