Mergulhe no React Native para desenvolvimento Android

Publicados: 2022-03-11

Alguns 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:

  1. Um contador básico com botões para aumentar e diminuir o contador
  2. Um aplicativo para pesquisar o subreddit r/pics
  3. Uma página de login genérica
  4. 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.

  1. A maneira convencional. Com a GUI do WebStorm ou com o comando do terminal: react-native init AwesomeToptalProject
  2. 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:

Layout gerado

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:

Layout gerado


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:

Layout gerado

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:

Layout gerado


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:

Layout gerado


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:

Layout gerado


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:

Layout gerado


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:

Layout gerado


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:

Layout gerado


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}); } } 
Aplicativo de decremento final

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.

Aplicativo de pesquisa final do reddit

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. Invoca render() 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 primeiro render() .
  • componentWillUnmount() - Chamado logo antes do componente ser desmontado e destruído.

Gráfico de ciclo de vida do componente

Componentes reutilizáveis

Muitas vezes precisamos criar componentes reutilizáveis ​​ao trabalhar no projeto. Existem duas maneiras de criar um componente:

  1. Criando uma classe que estende React.Component . Este método deve ser usado se precisarmos de métodos de ciclo de vida.
  2. 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.

Aplicativo de formulário de login gerado final

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 com yarn ou npm
  • Instale axios com yarn ou npm

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:

Aplicativo de navegação final no Android

iOS:

Aplicativo de navegação final no 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.

Relacionado: Construir um QR Scanner: um tutorial de câmera React Native