Mergulhe no React Native para desenvolvimento Android
Publicados: 2022-03-11Alguns anos atrás, um colega de trabalho meu me falou sobre o React Native. Eu estava muito cético. Argumentei que é apenas mais um framework multiplataforma que nunca funcionará na vida real – mal sabia eu o quão errado estava.
Os anos se passaram e as habilidades do React Native tornaram-se muito requisitadas. Já que fazia um tempo que eu aprendi algo novo, pensei por que não tentar? Hoje, sou um grande defensor do React Native.
Contras:
- Você não pode mais usar o Android Studio
- React Native não pode ser usado para todos os aplicativos ou recursos
- O React Native é um framework inovador e as atualizações podem ter um efeito negativo na sua base de código atual
- JavaScript não é uma linguagem estritamente tipada
- O React Native requer um mecanismo JavaScript para ser executado, o que pode torná-lo menos eficiente
Prós:
- Fácil de aprender
- Uma base de código compartilhada entre aplicativos Android e iOS, com apenas pequenos ajustes necessários para corresponder às experiências da plataforma
- Recarregamento ao vivo e a quente, o que significa que não há mais tempos de construção infinitos
- Componentes nativos para ambas as plataformas
- Melhorando constantemente
- Comunidade em crescimento ativo
- Grande número de bibliotecas
- Expo elimina a necessidade de possuir um Mac para desenvolver para iOS
- Redução nos recursos de mão de obra – embora você ainda precise de algum desenvolvimento nativo do Android/iOS, ele será pouco frequente.
Eu posso continuar, mas vamos parar por aqui e passar para o tópico desta postagem no blog. Neste post, vou criar quatro aplicativos Android com tecnologia React Native:
- Um contador básico com botões para aumentar e diminuir o contador
- Um aplicativo para pesquisar o subreddit r/pics
- Uma página de login genérica
- Um app para navegar no subreddit r/pics
IDE
Como mencionei acima, não há como usar o Android Studio para desenvolvimento React Native. Precisamos de um substituto. O React Native pode ser desenvolvido provavelmente em qualquer editor de texto moderno disponível no mercado (Atom, VS Code, Sublime Text, Brackets, etc.), mas como estamos chegando com a experiência do Android Studio, meu favorito é o WebStorm, que é construído pela mesma empresa. Embora o WebStorm seja um aplicativo pago (129 $ por ano), você pode instalar a versão Early Access dele. A compilação EAP do WebStorm é gratuita e bastante estável. Se você preferir um editor totalmente gratuito, vá para o VS Code. A Microsoft até desenvolveu um plugin React Native incrível para ele e funciona muito bem.
Criando um novo projeto
Pré-requisitos: Android SDK, Node e React Native instalados em seu computador.
Existem duas maneiras de criar um novo projeto React Native.
- A maneira convencional. Com a GUI do WebStorm ou com o comando do terminal:
react-native init AwesomeToptalProject
- Maneira mais fácil "Criar React Native App".
create-react-native-app AwesomeToptalProject
Se você usar create-react-native-app
, o projeto criado será inicializado com expo. Não entrarei em detalhes, mas basicamente significa que você não precisa ter o Xcode instalado para executar o aplicativo no iOS. Também é mais fácil manter o cliente sempre atualizado através da funcionalidade do expo.io e de alguns outros recursos. Mas você não pode adicionar código nativo. Assim, se você estiver desenvolvendo um recurso específico, pode ser necessário ejetar um aplicativo da expo e usar um projeto React Native regular.
Vou usar o primeiro método.
Vamos executar o projeto. Primeiro, abra um emulador ou conecte o dispositivo. Se você criou o projeto com a GUI do WebStorm, tudo o que você precisa fazer é escolher uma configuração. No canto superior direito do WebStorm, clique no menu suspenso à esquerda do botão Executar, escolha Android e clique em Executar ou Depurar. Se você criou o projeto com o Terminal, você pode adicionar uma nova configuração do React Native ou executá-la usando o Terminal:
cd AwesomeToptalProject react-native run-android
Se tudo correu bem, você será recebido com a seguinte tela:

Estrutura e configuração básica
Itens notáveis dentro do projeto são:
- android - projeto Android Studio pré-configurado com suporte React Native.
- ios - Projeto Xcode pré-configurado com suporte React Native.
- node_modules - Uma pasta contendo o framework React Native e outras bibliotecas Javascript.
- index.js - Um ponto de entrada para nosso aplicativo.
- App.js - Componente inicial carregado.
Vamos criar uma pasta “src” dentro da raiz do projeto e mover o App.js para lá. Você terá que atualizar as importações do index.js para corresponder ao novo local do App.js.
import App from './src/App';
Exclua tudo dentro do App.js e cole este código:
import React from 'react'; import {Text} from 'react-native'; export default class App extends React.Component { render() { return ( <Text>Hello TopTal</Text> ); } }
O código que colamos é bastante simples. Criamos uma classe App
(filho de React.Component
) que substitui o método render()
e retorna o componente Text
. React.Component
é a classe base para construir UI usando JSX. O modificador export default
torna a classe public
.
Agora estamos prontos para começar a projetar nosso layout.
Layout com Flexbox
Flexbox
é semelhante ao LinearLayout
, mas o Flexbox
vai muito além das habilidades do LinearLayout
.
Este trecho de 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>
Renderiza este layout:
Enquanto este 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>
Renderiza isso:
O código JSX parece familiar, hein?! Vamos criar um “dicionário” (ou uma folha de dicas) para layouts que sejam semelhantes em JSX e Android XML.
Observe que as funcionalidades não são necessariamente iguais. Estou tentando ajudar os novatos do React Native a entender a ideia do sistema de layout no React Native. Consulte o guia oficial para obter informações detalhadas.
Considere esta propriedade JSX:
flex: 1
É equivalente a isso:
android:layout_width="match_parent" android:layout_height="match_parent"
Este trecho de 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>
E este 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>
Ambos geram esta saída:
Da mesma forma, este 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>
E este 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>
Gere isso:
Para obter a posição correta dentro do contêiner, geralmente usaremos uma combinação das flexDirection
, alignItems
e justifyContent
.
Este 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>
E este 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>
Produzirá este layout:
Este 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>
E este 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>
Produzirá este layout:
Este 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>
E este 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>
Produzirá este layout:
Este 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>
e este 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>
Produzirá este layout:
Lição a ser aprendida: se tivermos 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
afeta o eixo Y e alignItems
afeta o eixo Y.
justificarConteúdo: 'flex-start' | gravidade="início|esquerda" |
alignItems: 'flex-start' | gravidade="início|esquerda" |
justificarConteúdo: 'flex-end' | gravidade="fim|direita" |
alignItems: 'flex-end' | gravidade="fim|direita" |
Tente você mesmo. Defina o valor justifyContent
como space-around
, space-between
e space-evenly
.
Gerenciamento de estado
Para atualizar o estado do aplicativo, você usará a variável de state
do React. Sempre que state
é atualizado, o render()
é invocado.
Copie o código abaixo para seu aplicativo:
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}); } }

Se você clicar nos botões DECREMENTAR e INCREMENTAR, verá que o texto é atualizado automaticamente para você. Não há necessidade de usar explicitamente textView.setText("Value " + number)
.

A funcionalidade de estado é útil por vários motivos:
- Facilidade de obter o valor – você sempre sabe onde e como obter o valor de uma variável específica.
- Os dados não estão vinculados a widgets específicos.
- Ter vários widgets dependentes da alteração de valor comum.
Criando um aplicativo de pesquisa para /r/pics
Agora que entendemos os fundamentos, vamos criar algo um pouco mais complexo: um aplicativo de busca para /r/pics. O Reddit fornece um endpoint de API JSON direto, para que não precisemos fazer missões secundárias para obter autenticação para que funcione corretamente.
O React Native fornece uma API Fetch integrada. Como a maioria de nós provavelmente está acostumada com o Retrofit e sua facilidade de uso, usaremos axios . Você pode instalar o axios através de um comando de terminal
usando yarn
(meu método preferido):
yarn add axios
ou usando npm
:
npm install axios
Importações:
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
Crie a classe:
export default class App extends React.Component { }
Para inicializar o estado. Vamos precisar de:
- loading - Para mostrar uma barra de progresso.
- error - Para mostrar se algum erro ocorreu ao fazer uma solicitação de API REST.
- imgUrl - Para visualizar a imagem pesquisada.
- texto - consulta de pesquisa.
state = {text: '', loading: false, error: null, imgUrl: null};
Adicione o código JSX. Temos um layout vertical com componentes TextInput
e 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> ); }
Coisas novas:
onChangeText={(text) => this.setState({text})} onSubmitEditing={() => this.searchPicture()} { this.state.imgUrl && <Image source={{uri: this.state.imgUrl}} style={{flex: 1}}/> }
O primeiro método faz um trabalho semelhante ao EditText
com o componente TextWatcher
. Sejamos honestos, é muito melhor em React Native.
O segundo método é invocado quando a tecla de retorno é pressionada no teclado ( et.OnEditorActionListener
) depois de acionar searchPicture()
.
A imagem é renderizada quando imgUrl
não é nulo ou indefinido, pois o operador '&&' não verifica um segundo argumento se o primeiro já for falso.
Você pode estar se perguntando por que this.state.imgUrl
é falso. Bem, ao usar operadores lógicos em JavaScript, qualquer coisa exceto '' (uma string vazia), 0
, false
, null
ou undefined
são true. Não há necessidade de uma verificação específica.
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}) }) }
Aqui vamos nós. O aplicativo deve funcionar como esperado agora. Digite uma string de pesquisa e pressione Enter.

Como nosso aplicativo também está pronto para renderizar ActivityIndicator
e erros, precisamos adicionar mais código após o componente 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> }
Você também pode mover componentes de renderização para fora do método render()
principal:
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> ); } }
Tudo o que resta são estilos. Coloque-os fora da classe 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 } });
Agora podemos adicionar mais alguns ajustes, como abrir automaticamente o teclado virtual quando o aplicativo é iniciado.
Observe que há uma maneira mais fácil de fazer TextInput
focar automaticamente ( autoFocus={true} prop
), mas para este exemplo, não a usaremos.
Adicione referência ao TextInput
com prop:
ref={ref => this.searchInput = ref}
E substitua o método de ciclo de vida componentDidMount()
assim:
componentDidMount(){ this.searchInput.focus(); }
Recarregue o aplicativo e o teclado será aberto automaticamente para nós.
Métodos de ciclo de vida do componente
Já criamos um componente, mas vamos passar pela vida de um componente.
Aqui está o fluxo do ciclo de vida do React:
-
constructor()
- O construtor é sempre chamado quando o aplicativo é iniciado -
static _getDerivedStateFromProps_(props, state)
- Chamado antes da renderização e após a atualização. Retorna o objeto para atualizar o estado. Retorna null para não atualizar nada. -
render()
- Render é necessário para cada classe React Component. É usado para renderizar View. -
componentDidMount()
- É invocado depois que o componente é renderizado e montado na árvore de exibição. -
shouldComponentUpdate(nextProps, nextState)
- Chamado após mudança de estado ou props. O padrão de retorno é true após cada atualização de estado. Invocarender()
se retornar true. -
getSnapshotBeforeUpdate(prevProps, prevState)
- Chamado logo antes da saída renderizada ser confirmada. -
componentDidUpdate(prevProps, prevState, snapshot)
- Chamado após renderizar uma nova atualização. Não é chamado após o primeirorender()
. -
componentWillUnmount()
- Chamado logo antes do componente ser desmontado e destruído.
Componentes reutilizáveis
Muitas vezes precisamos criar componentes reutilizáveis ao trabalhar no projeto. Existem duas maneiras de criar um componente:
- Criando uma classe que estende
React.Component
. Este método deve ser usado se precisarmos de métodos de ciclo de vida. - Escrevendo uma função que retorna View para uma sintaxe mais simples.
Como já criamos as classes Component, vamos criar uma função para esta instância.
Suponha que precisamos de um analógico para <CardView>
. Crie uma pasta “comum” no diretório ./src
.
Crie 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
usando nosso novo layout 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' } }) } });
Importe a classe LoginForm
na classe App
e envolva-a com View
<View style={{flex: 1, justifyContent: 'center'}}> <LoginForm/> </View>
Se você ajustar os parâmetros nos estilos, poderá obter algo com uma aparência muito melhor.
Navegação
A navegação para diferentes cenas é uma parte essencial para a maioria dos aplicativos. Vamos criar um aplicativo de navegador Reddit /r/pics.
Criar navegação no React Native é bastante fácil.
Pré-requisitos
- Instale o react
react-navigation
comyarn
ounpm
- Instale
axios
comyarn
ounpm
Vamos começar criando dois componentes diferentes.
Nota: A maior parte do código abaixo já deve ser familiar para você. Vou colar a aula inteira.
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}}/>) } }
As navigationOptions
serão automaticamente invocadas pelo React-Navigation.
Agora vamos para o App.js
Nota: Existem muitos tipos de navegação em React-Navigation. Hoje, vamos nos concentrar no StackNavigation
. Consulte o site oficial para obter informações detalhadas.
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' } );
Como você pode ver, tudo o que precisamos fazer é criar um roteador de navegação e fazer o aplicativo renderizá-lo. Se tudo correu bem, teremos um aplicativo de navegador Reddit /r/pics funcional.
Android:
iOS:
React Native é incrível!
Desde que comecei a programar, tive experiências de desenvolvimento puramente mobile. Mas agora posso codificar praticamente qualquer coisa com React: mobile, desktop e web.
Se você decidir começar a desenvolver seu próximo aplicativo incrível usando o React Native, verá que ele tem suas peculiaridades e alguns bugs aqui e ali, mas o React Native é muito funcional e ideal para a maioria dos projetos.