Погрузитесь в React Native для разработки под Android
Опубликовано: 2022-03-11Несколько лет назад мой коллега рассказал мне о React Native. Я был настроен очень скептически. Я утверждал, что это просто еще один кроссплатформенный фреймворк, который никогда не будет работать в реальной жизни — я и не подозревал, насколько ошибался.
Прошли годы, и навыки React Native стали очень востребованы. Поскольку я давно узнал что-то новое, я подумал, почему бы не попробовать? Сегодня я большой сторонник React Native.
Минусы:
- Вы больше не можете использовать Android Studio
- React Native нельзя использовать для каждого приложения или функции.
- React Native — это новый фреймворк, и обновления могут негативно повлиять на вашу текущую кодовую базу.
- JavaScript не является строго типизированным языком
- React Native требует запуска движка JavaScript, что может сделать его менее производительным.
Плюсы:
- Легко учить
- Общая кодовая база приложений для Android и iOS с небольшими изменениями, необходимыми для соответствия платформенным возможностям.
- Живая и горячая перезагрузка, что означает отсутствие бесконечного времени сборки
- Нативные компоненты для обеих платформ
- Постоянно совершенствуемся
- Активно растущее сообщество
- Огромное количество библиотек
- Expo избавляет от необходимости иметь Mac для разработки под iOS
- Сокращение трудовых ресурсов — хотя вам все еще может понадобиться нативная разработка для Android/iOS, это будет нечасто.
Я могу продолжать и продолжать, но давайте остановимся здесь и перейдем к теме этого сообщения в блоге. В этом посте я собираюсь создать четыре приложения для Android на базе React Native:
- Базовый счетчик с кнопками для увеличения и уменьшения счетчика
- Приложение для поиска в сабреддите r/pics
- Общая страница входа
- Приложение для просмотра сабреддита r/pics
IDE
Как я упоминал выше, мы не можем использовать Android Studio для разработки React Native. Нам нужен заменитель. React Native может быть разработан, вероятно, в любом современном текстовом редакторе, доступном там (Atom, VS Code, Sublime Text, Brackets и т. д.), но, поскольку мы работаем с Android Studio, мой любимый — WebStorm, созданный той же компанией. Хотя WebStorm является платным приложением (129 $ в год), вы можете установить его версию раннего доступа. EAP-сборка WebStorm бесплатна и достаточно стабильна. Если вы предпочитаете полностью бесплатный редактор, выберите VS Code. Microsoft даже разработала для него замечательный плагин React Native, и он работает очень хорошо.
Создание нового проекта
Предварительные требования: Android SDK, Node и React Native, установленные на вашем компьютере.
Есть два способа создать новый проект React Native.
- Обычный способ. Либо с графическим интерфейсом WebStorm, либо с помощью команды терминала:
react-native init AwesomeToptalProject
- Более простой способ «Создать приложение React Native».
create-react-native-app AwesomeToptalProject
Если вы используете create-react-native-app
, созданный проект будет загружен с помощью expo. Я не буду вдаваться в подробности, но в основном это означает, что вам не нужно устанавливать Xcode для запуска приложения на iOS. Кроме того, проще всегда поддерживать клиент в актуальном состоянии благодаря функциям expo.io и некоторым другим функциям. Но вы не можете добавить нативный код. Таким образом, если вы разрабатываете определенную функцию, вам может потребоваться удалить приложение из выставки и вместо этого использовать обычный проект React Native.
Я буду использовать первый метод.
Запустим проект. Сначала откройте эмулятор или подключите устройство. Если вы создали проект с графическим интерфейсом WebStorm, все, что вам нужно сделать, это выбрать конфигурацию. В правом верхнем углу WebStorm щелкните раскрывающийся список слева от кнопки «Выполнить», выберите «Android» и нажмите «Выполнить» или «Отладка». Если вы создали проект с помощью терминала, вы можете либо добавить новую конфигурацию React Native, либо запустить его с помощью терминала:
cd AwesomeToptalProject react-native run-android
Если все прошло хорошо, вас встретит следующий экран:

Структура и базовая настройка
Примечательные элементы внутри проекта:
- android — проект Android Studio с предварительно настроенной поддержкой React Native.
- ios — проект Xcode с предварительно настроенной поддержкой React Native.
- node_modules — папка, содержащая фреймворк React Native и другие библиотеки Javascript.
- index.js — точка входа для нашего приложения.
- App.js — начальный компонент загружен.
Давайте создадим папку «src» внутри корня проекта и переместим туда App.js. Вам придется обновить импорт index.js, чтобы он соответствовал новому расположению App.js.
import App from './src/App';
Удалите все внутри App.js и вставьте этот код:
import React from 'react'; import {Text} from 'react-native'; export default class App extends React.Component { render() { return ( <Text>Hello TopTal</Text> ); } }
Код, который мы вставили, довольно прост. Мы создали класс App
(дочерний React.Component
), который переопределяет метод render()
и возвращает компонент Text
. React.Component
— это базовый класс для создания пользовательского интерфейса с использованием JSX. Модификатор export default
делает класс public
.
Теперь мы готовы приступить к разработке нашего макета.
Макет с Flexbox
Flexbox
похож на LinearLayout
, но Flexbox
намного превосходит LinearLayout
.
Этот фрагмент JSX:
<View style={{ flex: 1, flexDirection: 'row' }}> <View style={{ width: 100, height: 100, backgroundColor: '#9575CD' }}/> <View style={{ width: 100, height: 100, backgroundColor: '#7E57C2' }}/> <View style={{ width: 100, height: 100, backgroundColor: '#673AB7' }}/> </View>
Отображает этот макет:
Хотя этот XML:
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <View android:layout_width="100dp" android:layout_height="100dp" android:background="#9575CD" /> <View android:layout_width="100dp" android:layout_height="100dp" android:background="#7E57C2" /> <View android:layout_width="100dp" android:layout_height="100dp" android:background="#673AB7" /> </LinearLayout>
Отображает это:
Код JSX выглядит знакомо, да?! Давайте создадим «словарь» (или шпаргалку) для макетов, используя похожий вид в JSX и Android XML.
Обратите внимание, что функциональные возможности не обязательно равны. Я пытаюсь помочь новичкам в React Native понять идею системы компоновки в React Native. Пожалуйста, обратитесь к официальному руководству для получения подробной информации.
Рассмотрим это свойство JSX:
flex: 1
Это эквивалентно этому:
android:layout_width="match_parent" android:layout_height="match_parent"
Этот фрагмент JSX:
<View style={{flex: 1, flexDirection: 'row'}}> <View style={{ width: 100, height: 100, backgroundColor: '#9575CD'}}/> <View style={{ width: 100, height: 100, backgroundColor: '#7E57C2'}}/> <View style={{ width: 100, height: 100, backgroundColor: '#673AB7'}}/> </View>
И этот XML:
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <View android:layout_width="100dp" android:layout_height="100dp" android:background="#9575CD" /> <View android:layout_width="100dp" android:layout_height="100dp" android:background="#7E57C2" /> <View android:layout_width="100dp" android:layout_height="100dp" android:background="#673AB7" /> </LinearLayout>
Оба генерируют этот вывод:
Точно так же этот JSX:
<View style={{flex: 1, flexDirection: 'column'}}> <View style={{ width: 100, height: 100, backgroundColor: '#9575CD'}}/> <View style={{ width: 100, height: 100, backgroundColor: '#7E57C2'}}/> <View style={{ width: 100, height: 100, backgroundColor: '#673AB7'}}/> </View>
И этот XML:
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <View android:layout_width="100dp" android:layout_height="100dp" android:background="#9575CD" /> <View android:layout_width="100dp" android:layout_height="100dp" android:background="#7E57C2" /> <View android:layout_width="100dp" android:layout_height="100dp" android:background="#673AB7" /> </LinearLayout>
Сгенерируйте это:
Чтобы добиться правильного положения внутри контейнера, мы чаще всего будем использовать комбинацию flexDirection
, alignItems
и justifyContent
.
Этот JSX:
<View style={{flex: 1, flexDirection: 'column', alignItems: 'center'}}> <View style={{ width: 100, height: 100, backgroundColor: '#9575CD'}}/> <View style={{ width: 100, height: 100, backgroundColor: '#7E57C2'}}/> <View style={{ width: 100, height: 100, backgroundColor: '#673AB7'}}/> </View>
И этот XML:
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_horizontal" android:orientation="vertical"> <View android:layout_width="100dp" android:layout_height="100dp" android:background="#9575CD" /> <View android:layout_width="100dp" android:layout_height="100dp" android:background="#7E57C2" /> <View android:layout_width="100dp" android:layout_height="100dp" android:background="#673AB7" /> </LinearLayout>
Создаст этот макет:
Этот JSX:
<View style={{flex: 1, flexDirection: 'column', justifyContent: 'center'}}> <View style={{ width: 100, height: 100, backgroundColor: '#9575CD'}}/> <View style={{ width: 100, height: 100, backgroundColor: '#7E57C2'}}/> <View style={{ width: 100, height: 100, backgroundColor: '#673AB7'}}/> </View>
И этот XML
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_vertical" android:orientation="vertical"> <View android:layout_width="100dp" android:layout_height="100dp" android:background="#9575CD" /> <View android:layout_width="100dp" android:layout_height="100dp" android:background="#7E57C2" /> <View android:layout_width="100dp" android:layout_height="100dp" android:background="#673AB7" /> </LinearLayout>
Создаст этот макет:
Этот JSX:
<View style={{flex: 1, flexDirection: 'row', justifyContent: 'center'}}> <View style={{ width: 100, height: 100, backgroundColor: '#9575CD'}}/> <View style={{ width: 100, height: 100, backgroundColor: '#7E57C2'}}/> <View style={{ width: 100, height: 100, backgroundColor: '#673AB7'}}/> </View>
И этот XML:
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_horizontal" android:orientation="horizontal"> <View android:layout_width="100dp" android:layout_height="100dp" android:background="#9575CD" /> <View android:layout_width="100dp" android:layout_height="100dp" android:background="#7E57C2" /> <View android:layout_width="100dp" android:layout_height="100dp" android:background="#673AB7" /> </LinearLayout>
Создаст этот макет:
Этот JSX:
<View style={{flex: 1, flexDirection: 'row', justifyContent: 'center', alignItems: 'center'}}> <View style={{ width: 100, height: 100, backgroundColor: '#9575CD'}}/> <View style={{ width: 100, height: 100, backgroundColor: '#7E57C2'}}/> <View style={{ width: 100, height: 100, backgroundColor: '#673AB7'}}/> </View>
и этот XML:
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical"> <View android:layout_width="100dp" android:layout_height="100dp" android:background="#9575CD" /> <View android:layout_width="100dp" android:layout_height="100dp" android:background="#7E57C2" /> <View android:layout_width="100dp" android:layout_height="100dp" android:background="#673AB7" /> </LinearLayout>
Создаст этот макет:
Урок, который необходимо усвоить: если у нас есть flexDirection: row',
alignItems works on Y axis and
justifyContent works on X axis. Everything is mirrored for
works on X axis. Everything is mirrored for
flexDirection: column' - justifyContent
влияет на ось Y, а alignItems
влияет на ось Y.
justifyContent: «гибкий старт» | гравитация = "старт | слева" |
alignItems: «гибкий старт» | гравитация = "старт | слева" |
justifyContent: «гибкий конец» | гравитация = "конец | справа" |
alignItems: 'flex-end' | гравитация = "конец | справа" |
Попробуй сам. Установите значение justifyContent
в space-around
, space-between
и space-evenly
.
Государственное управление
Для обновления состояния приложения вы будете использовать переменную state
React. Всякий раз, когда state
обновляется, вызывается render()
.
Скопируйте приведенный ниже код в свое приложение:
import React from 'react'; import {Button, Text, View} from 'react-native'; export default class App extends React.Component { /* Initialize state object with variable 'number' set to 0 and variable name with value of empty string */ state = {number: 0}; render() { return ( <View style={{ flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', flex: 1, padding: 20 }}> <Button title='Decrement' color='#e57373' onPress={() => this.decrement()}/> <Text> {/* Text will be automatically updated whenever state.number has changed value */} Value = {this.state.number} </Text> <Button title='Increment' color='#64B5F6' {/* Set listener for click */} onPress={() => this.increment()}/> </View> ); } //Declaration of decrement function decrement() { //To update the state we need invoke this.setState //with new value for variable 'number' this.setState({number: this.state.number - 1}); } increment() { this.setState({number: this.state.number + 1}); } }

Если вы нажмете кнопки DECREMENT и INCREMENT, вы увидите, что текст автоматически обновляется. Нет необходимости явно использовать textView.setText("Value " + number)
.

Функциональность состояния удобна по нескольким причинам:
- Простота получения значения — вы всегда знаете, где и как получить значение для конкретной переменной.
- Данные не привязаны к конкретным виджетам.
- Наличие нескольких виджетов, зависящих от общего изменения значения.
Создание приложения поиска для /r/pics
Теперь, когда мы разобрались с основами, давайте создадим нечто более сложное: приложение для поиска /r/pics. Reddit предоставляет простую конечную точку JSON API, поэтому нам не придется выполнять побочные квесты, чтобы получить аутентификацию, чтобы она работала правильно.
React Native предоставляет встроенный API Fetch. Поскольку большинство из нас, вероятно, привыкли к Retrofit и его простоте использования, мы будем использовать axios . Вы можете установить axios через команду терминала
используя yarn
(мой предпочтительный метод):
yarn add axios
или используя npm
:
npm install axios
Импорт:
import React from 'react'; import { TextInput, View, Text, Image, ActivityIndicator, Platform, StyleSheet } from 'react-native'; import axios from 'axios'; TextInput = EditText, ActivityIndicator = ProgressBar Platform - Platform detecting module StyleSheet - Module for creating stylesheets and moving them away from JSX
Создайте класс:
export default class App extends React.Component { }
Для инициализации состояния. Нам понадобится:
- loading — для отображения индикатора выполнения.
- error — чтобы показать, произошла ли какая-то ошибка при выполнении запроса REST API.
- imgUrl — для предварительного просмотра искомого изображения.
- текст - поисковый запрос.
state = {text: '', loading: false, error: null, imgUrl: null};
Добавьте код JSX. У нас есть вертикальная компоновка с компонентами TextInput
и Image
.
render() { return ( //Predefined style. See below <View style={styles.containerStyle}> {/* returnKeyType ~ imeOptions onSubmitEditing ~ et.OnEditorActionListener */} <TextInput style={styles.textInputStyle} placeholder="Enter text to search an image" returnKeyType='search' autoFocus={true} onChangeText={(text) => this.setState({text})} onSubmitEditing={() => this.searchPicture()}/> {/* Render error Image component if this.state.imgUrl is not equal to null */} { this.state.imgUrl && <Image source={{uri: this.state.imgUrl}} style={{flex: 1}}/> } </View> ); }
Новый материал:
onChangeText={(text) => this.setState({text})} onSubmitEditing={() => this.searchPicture()} { this.state.imgUrl && <Image source={{uri: this.state.imgUrl}} style={{flex: 1}}/> }
Первый метод работает аналогично EditText
с компонентом TextWatcher
. Будем честными, в React Native намного приятнее.
Второй метод вызывается при нажатии клавиши возврата на клавиатуре ( et.OnEditorActionListener
) после searchPicture()
.
Изображение отображается, когда imgUrl
не является нулевым или неопределенным, поскольку оператор «&&» не проверяет наличие второго аргумента, если первый уже имеет значение false.
Вам может быть интересно, почему this.state.imgUrl
является ложным. Что ж, при использовании логических операторов в JavaScript все, кроме '' (пустой строки), 0
, false
, null
или undefined
является истинным. Специальной проверки не требуется.
searchPicture() { //Default state this.setState({loading: true, error: null, imgUrl: null}); axios.get('https://www.reddit.com/r/pics/search.json', { params: { //the get param map restrict_sr: 'on', //search only /r/pics limit: 1, //limit to one search item sort: 'new', //sort by creation date q: this.state.text //our search query } }).then(response => { //promise is resolved and 'then' block is triggered //set state with new values this.setState({ imgUrl: response.data.data.children[0] .data.preview.images[0].source.url, error: null, loading: false }) }).catch(error => {//Some error occurred //set error this.setState({error: error.message, loading: false, imgUrl: null}) }) }
Вот так. Теперь приложение должно работать как положено. Введите строку поиска и нажмите клавишу возврата.

Поскольку наше приложение также готово отображать ActivityIndicator
и ошибки, нам нужно добавить еще немного кода после компонента Image
:
{ //Separate method this.renderProgress() } {/* Render error Text component if this.state.error is not equal to null */} { this.state.error && <Text style={{margin: 16, color: 'red'}}> {this.state.error} </Text> }
Вы также можете перемещать компоненты рендеринга вне основного метода render()
:
renderProgress() { //If this.state.loading is true //return View containing a progressbar //View takes style array if (this.state.loading === true) { return ( <View style={ [styles.containerStyle, {justifyContent: 'center'}]}> <ActivityIndicator color='#e57373'/> </View> ); } }
Осталось только стили. Поместите их вне класса App
.
const styles = StyleSheet.create({ containerStyle: { flexDirection: 'column', flex: 1, //Since React Native is cross platform //let's handle both platforms. //Add top margin to fix status bar overlap marginTop: Platform.OS === 'ios' ? 20 : 0, }, textInputStyle: { marginLeft: 16, marginRight: 16, height: Platform.OS === 'ios' ? 30 : undefined } });
Теперь мы можем добавить еще несколько настроек, таких как автоматическое открытие программной клавиатуры при запуске приложения.
Обратите внимание, что есть более простой способ заставить TextInput
автоматически фокусироваться ( autoFocus={true} prop
), но в этом примере мы не будем его использовать.
Добавьте ссылку на TextInput
с опорой:
ref={ref => this.searchInput = ref}
И переопределите метод жизненного цикла componentDidMount()
следующим образом:
componentDidMount(){ this.searchInput.focus(); }
Перезагрузите приложение, и клавиатура автоматически откроется для нас.
Методы жизненного цикла компонентов
Мы уже создали компонент, но давайте пройдемся по жизни компонента.
Вот поток жизненного цикла React:
-
constructor()
— конструктор всегда вызывается при запуске приложения. -
static _getDerivedStateFromProps_(props, state)
— вызывается перед рендерингом и после обновления. Возвращает объект для обновления состояния. Верните null, чтобы ничего не обновлять. -
render()
— рендеринг требуется для каждого класса React Component. Он используется для рендеринга View. -
componentDidMount()
— вызывается после рендеринга компонента и его подключения к дереву представления. -
shouldComponentUpdate(nextProps, nextState)
— вызывается после изменения состояния или свойств. Возвращаемое значение по умолчанию равно true после каждого обновления состояния. Вызываетrender()
, если возвращает true. -
getSnapshotBeforeUpdate(prevProps, prevState)
— вызывается непосредственно перед фиксацией обработанного вывода. -
componentDidUpdate(prevProps, prevState, snapshot)
— вызывается после рендеринга нового обновления. Он не вызывается после первогоrender()
. -
componentWillUnmount()
— вызывается непосредственно перед размонтированием и уничтожением компонента.
Многоразовые компоненты
Нам часто приходится создавать повторно используемые компоненты при работе над проектом. Существует два способа создания компонента:
- Создание класса, который расширяет
React.Component
. Этот метод следует использовать, если нам нужны методы жизненного цикла. - Написав функцию, которая возвращает View для более простого синтаксиса.
Поскольку мы уже создали классы компонентов, давайте создадим функцию для этого экземпляра.
Предположим, нам нужен аналог <CardView>
. Создайте «общую» папку в каталоге ./src
.
Создайте CardView.js
.
import React from "react"; import {View} from "react-native"; export default CardView = (props) => { return ( //Style will be merged from default containerStyle //and props.style. props.style attributes will override //values if parameters are same. <View style={{...styles.containerStyle, ...props.style}}> {/* props.children contain subviews add this line if the component is container */} {props.children} </View> ); }; const styles = { containerStyle: { borderRadius: 4, margin: 5, padding: 5, elevation: 5, shadowColor: 'black', shadowRadius: 5, shadowOpacity: 0.5, shadowOffset: {width: 0, height: 3}, backgroundColor: 'white' } };
LoginForm
с использованием нашего нового макета CardView
:
import React from "react"; import {TextInput, Platform, Button, StyleSheet} from "react-native"; import CardView from "../common/components/CardView"; export default class LoginForm extends React._Component _{ render() { return ( //Override default style <CardView style={{ borderRadius: 4, backgroundColor: '#fff' }}> <TextInput placeholder="Email" style={styles.textInputStyle}/> <TextInput placeholder="Password" style={styles.textInputStyle} secureTextEntry={true}/> <Button color="#841584" title="Login" onPress={() => console.log("onLoginPress")} buttonStyle={styles.buttonStyle}/> </CardView> ); } } const styles = StyleSheet.create({ buttonStyle: { elevation: 5, height: 40 }, textInputStyle: { padding: 10, //Additional params to make //iOS inputs prettier ...Platform.select({ ios: { borderRadius: 2, marginTop: 5, backgroundColor: '#eeeeee' } }) } });
Импортируйте класс LoginForm
в класс App
и оберните его View
<View style={{flex: 1, justifyContent: 'center'}}> <LoginForm/> </View>
Если вы настроите параметры в стилях, вы можете получить что-то, что выглядит намного лучше.
Навигация
Переход к различным сценам является важной частью большинства приложений. Мы собираемся создать браузерное приложение Reddit /r/pics.
Создать навигацию в React Native довольно просто.
Предпосылки
- Установите
react-navigation
с помощьюyarn
илиnpm
- Установите
axios
с помощьюyarn
илиnpm
Начнем с создания двух разных компонентов.
Примечание. Большая часть приведенного ниже кода должна быть вам уже знакома. Я наклею весь класс.
PictureList.js:
import React from 'react'; import { ActivityIndicator, FlatList, Image, Text, TouchableHighlight, View } from "react-native"; import axios from "axios"; import CardView from "../common/CardView"; export default class PictureList extends React.Component { state = {loading: true, error: null, posts: null}; componentDidMount() { axios.get('https://www.reddit.com/r/pics.json') .then(response => { this.setState({ posts: response.data.data.children, loading: false }) }).catch(error => { this.setState({ error: error.message, loading: false }) }) } render() { return ( <View style={{flex: 1, justifyContent: 'center'}}> // FlatList ~ ListView // data - DataSource for the List // renderItem - function returns View item // keyExtractor - Unique id for items {this.state.posts && <FlatList data={this.state.posts} renderItem={this.renderItem.bind(this)} keyExtractor={(item) => (item.data.id + '')}/>} {this.state.loading && <ActivityIndicator size="large" color="#f4511e"/>} </View> ); } navigateToPicture(title, url) { this.props.navigation.navigate('PicturePreview', { 'title': title, 'url': url }) } renderItem(item) { //Destructuring values from item //Read more 'ES6 destructuring' const {data} = item.item; const {title} = data; const {url} = data.preview.images[0].source; return ( //Clickable view <TouchableHighlight onPress={() => this.navigateToPicture(title, url)}> {/Reusing our CardView/} <CardView> <Image style={{height: 150}} source={{uri: url}}/> <Text style={{padding: 5}}>{title}</Text> </CardView> </TouchableHighlight> ) } }
PicturePreview.js
:
import React from 'react'; import {Image} from "react-native"; export default class PicturePreview extends React.Component { //Destructure navigation //Set title to header static _navigationOptions = ({navigation}) => ({ title: navigation.state.params.title }); render() { const {url} = this.props.navigation.state.params; return (<Image style={{flex: 1}} source={{uri: url}}/>) } }
navigationOptions
будет автоматически вызываться React-Navigation.
Теперь давайте перейдем к App.js
Примечание. В React-Navigation существует множество типов навигации. Сегодня мы сосредоточимся на StackNavigation
. Пожалуйста, обратитесь к официальному сайту для получения подробной информации.
import React from 'react'; import {createStackNavigator} from "react-navigation"; import PictureList from "./components/PictureList"; import PicturePreview from "./components/PicturePreview"; export default class App extends React.Component { render() { return ( <Router/> ); } } //Customize the header_ const NavigationOptions = { headerTintColor: '#fff', headerStyle: { backgroundColor: '#f4511e', } }; //Create the router. const Router = createStackNavigator({ //Name the screen 'PictureList': { //Link the Component screen: PictureList, //Additional navigation options navigationOptions: { title: '/r/pics Browser', ...NavigationOptions } }, 'PicturePreview': { screen: PicturePreview, navigationOptions: NavigationOptions } }, { //Root initialRouterName: 'PictureList' } );
Как видите, все, что нам нужно сделать, это создать навигационный маршрутизатор и заставить приложение отображать его. Если все пойдет хорошо, у нас будет работающее браузерное приложение Reddit /r/pics.
Андроид:
iOS:
React Native — это потрясающе!
С тех пор, как я начал программировать, у меня был опыт исключительно мобильной разработки. Но теперь я могу кодировать с помощью React практически все: для мобильных устройств, компьютеров и веб-приложений.
Если вы решите начать разработку своего следующего замечательного приложения с помощью React Native, вы обнаружите, что у него есть свои особенности и некоторые ошибки здесь и там, но React Native очень функционален и идеально подходит для большинства проектов.