Como criar apps com React Native em 2023

Como criar apps com React Native em 2023

Tags
React Native
Published
May 3, 2023
Author
Matheus Costa
Neste post estarei compartilhando e documentando minha experiência durante o processo de criação de aplicativos Android e iOS utilizando React Native.

1) Configuração do ambiente

1.2) Quais as ferramentas de desenvolvimento?

1.3) Criando um app em React Native (com Expo)

Criando o app

npx create-expo-app NomeApp
  • O comando acima irá criar um o aplicativo utilizando o Expo.

Executando o app

cd NomeApp npx expo start
Observações:
  • Instalar o app Expo Go (Android/iOS*)
  • Ler o QR-Code gerado através do aplicativo Expo Go;
    • *no iOS basta ler o QR-Code com o aplicativo de câmera;

1.4) Criando um app em React Native (por CLI)

Observações:
  • Ambiente: Windows
  • Dispositivo: Android
  • Conectar o dispositivo Android no computador via cabo USB;
  • No aparelho, habilitar o modo de desenvolvedor e permitir a depuração USB;
  • Ao conectar o celular no computador, permitir a transferência de arquivos;

Criando o app

npx react-native@latest init NomeApp
  • O comando acima irá criar todos os arquivos necessários para o app;

Iniciando o app

cd NomeApp npx react-native run-android
  • O aplicativo será instalado automaticamente no aparelho Android
  • Também é possível iniciar com Metro* separadamente com o comando:
npx react-native start
  • *o Metro é muito parecido com o webpack (React para web) — só que p/ para apps — ele é um empacotador de JavaScript.

Atalhos

  • Podemos personalizar os atalhos para executar o app em modo de desenvolvimento;
  • Para isso, basta editar o arquivo package.json.
"scripts": { "android": "react-native run-android", "ios": "react-native run-ios", "lint": "eslint .", "start": "react-native start", "dev": "react-native start --reset-cache", "test": "jest" },
  • No exemplo acima foi adicionado o atalho “dev” com —reset-cache.
  • Assim podemos iniciar o modo de desenvolvimento com:
npm run dev
 

2) O básico

2.1) O que é o React Native?

  • React Native é uma estrutura híbrida e de código aberto para criar apps para Android e iOS usando React;

2.2) Desenvolvimento Nativo x Híbrido

  • Para criar apps nativos em Android utilizamos a linguagem Java ou Kotlin;
  • Para criar apps nativos para iOS é necessário codificar em Swift ou Objective-C;
  • O React Native é uma estrutura híbrida e utiliza a linguagem Javascript para criar as visualizações correspondentes do Android e iOS em tempo de execução;

2.3) Componentes principais

  • O React Native possui muitos componentes principais, como por exemplo:
React Native
Android
iOS
Web (similaridade)
<View>
<ViewGroup>
<UIView>
<div>
<Text>
<TextView>
<UITextView>
<p>
<Image>
<ImageView>
<UIImageImage>
<img>
<ScrollView>
<ScrollView>
<UIScrollView>
<div>
<TextInput>
<EditText>
<UITextField>
<input type="text">

2.3.1) Amostra das visualizações no Android x iOS

notion image

2.4) Fundamentos de React

  • React Native é executado com base no React, por isso, é necessário saber os fundamentos de:
    • 2.4.1) componentes
    • 2.4.2) JSX
    • 2.4.3) props
    • 2.4.4) estado

2.4.1) Componentes

  • Um componente é um elemento básico da interface do usuário;
  • Podemos criar componentes de função (hooks com estado) e com classes (forma antiga);
  • O React Native irá renderizar no aparelho do usuário o componente de acordo com o sistema operacional do dispositivo (iOS ou Android);
import React from 'react'; import {Text} from 'react-native'; const Cat = () => { return <Text>Hello, I am your cat!</Text>; }; export default Cat;

2.4.2) JSX

  • JSX é uma extensão da sintaxe do JavaScript que permite escrever HTML dentro do JavaScript;
  • Em JSX podemos misturar JavaScript e HTML (ou XML) em um único arquivo;
  • Como JSX é JavaScript, podemos usar variáveis dentro dele;
  • Qualquer expressão JavaScript funcionará entre chaves no JSX, como por exemplo: 
import React from 'react'; import {Text} from 'react-native'; const getFullName = ( firstName: string, secondName: string, thirdName: string, ) => { return firstName + ' ' + secondName + ' ' + thirdName; }; const Cat = () => { return <Text>Hello, I am {getFullName('Rum', 'Tum', 'Tugger')}!</Text>; }; export default Cat;

2.4.3) Props

  • Props é uma abreviação para propriedades;
  • As propriedades permitem personalizar os componentes React, por exemplo:
import React from 'react'; import {Text, View} from 'react-native'; const Cat = props => { return ( <View> <Text>Hello, I am {props.name}!</Text> </View> ); }; const Cafe = () => { return ( <View> <Cat name="Maru" /> <Cat name="Jellylorum" /> <Cat name="Spot" /> </View> ); }; export default Cafe;

2.4.4) Estado

  • Estado é a forma de armazenar dados de um componente;
  • O estado fornece memória aos componentes;
  • Ele é útil para lidar com dados que mudam com o tempo ou que vêm da interação do usuário;
  • É possível adicionar estado a um componente React usando o hook useState;
  • useState é um hook que permite adicionar estado aos componentes da função;
import React, {useState} from 'react'; import {Button, Text, View} from 'react-native'; const Cat = props => { const [isHungry, setIsHungry] = useState(true); return ( <View> <Text> I am {props.name}, and I am {isHungry ? 'hungry' : 'full'}! </Text> <Button onPress={() => {setIsHungry(false)}} disabled={!isHungry} title={isHungry ? 'Pour me some milk, please!' : 'Thank you!'} /> </View> ); }; const Cafe = () => { return ( <Cat name="Munkustrap" /> ); }; export default Cafe;

2.4.5) Fragmentos

  • As tags “vazias” <> e </> acima são bits do JSX chamadas de fragmentos.
  • Fragmentos permitem envolver todo código sem precisar incluir um elemento extra e desnecessário, como uma View, por exemplo.
const Cafe = () => { return ( <> <Cat name="Munkustrap" /> <Cat name="Spot" /> </> ); };

2.5) Código específico Android/iOS

  • Com React Native é possível implementar componentes visuais separados p/ Android e iOS;
  • Há duas maneiras de separar o código por plataforma:
    • 1) Usando o Platform Module;
    • 2) Usando extensões de arquivos específicas;

Platform Module

  • Essa opção é recomendada para pequenas partes de código;
  • É possível usar a lógica de detecção para implementar o código específico da plataforma;
  • Platform:
import {Platform, StyleSheet} from 'react-native'; const styles = StyleSheet.create({ height: Platform.OS === 'ios' ? 200 : 100, });
  • Platform.select - pode ser: 'ios' | 'android' | 'native' | 'default'
import {Platform, StyleSheet} from 'react-native'; const styles = StyleSheet.create({ container: { flex: 1, ...Platform.select({ ios: { backgroundColor: 'red', }, android: { backgroundColor: 'green', }, default: { // outras plataformas, web por exemplo backgroundColor: 'blue', }, }), }, });
  • Detectar a versão do Android:
import {Platform} from 'react-native'; if (Platform.Version === 25) { console.log('Running on Nougat!'); }
  • Detectar a versão do iOS:
import {Platform} from 'react-native'; const majorVersionIOS = parseInt(Platform.Version, 10); if (majorVersionIOS <= 9) { console.log('Work around a change in behavior'); }

Extensões de arquivos específicas

  • Recomendado para códigos específicos da plataforma mais complexos;
  • Com essa opção é possível dividir o código em arquivos separados;
  • Para utilizar esse opção é só criar o componente com o nome de cada plataforma, por exemplo:
BigButton.ios.js BigButton.android.js
  • Depois, basta importar o componente e o React Native selecionará automaticamente o arquivo correto com base na plataforma em execução:
import BigButton from './BigButton';
 

3) Design

3.1) Style

  • Todos os componentes principais aceitam a propriedade style
  • Os nomes dos estilos e valores correspondem à maneira como o CSS funciona na web;
  • Porém os nomes são escritos no formato camelCase, por exemplo:
    • backgroundColor ao invés de background-color;
  • A medida que o componente cresce em complexidade é mais limpo usar StyleSheet.create
import React from 'react'; import {StyleSheet, Text, View} from 'react-native'; const styles = StyleSheet.create({ container: { marginTop: 50, }, red: { color: 'red', }, }); const LotsOfStyles = () => { return ( <View style={styles.container}> <Text style={styles.red}>just red</Text> </View> ); }; export default LotsOfStyles;

3.2) Largura e altura (Width/Height)

  • Todas as dimensões no React Native não precisam de unidade (px, rem, etc)
  • As dimensões representam pixels independentes da densidade;
import React from 'react'; import {View} from 'react-native'; const FixedDimensionsBasics = () => { return ( <View> <View style={{ width: 100, height: 100, backgroundColor: 'skyblue', }} /> </View> ); }; export default FixedDimensionsBasics;
  • Também é possível utilizar valores percentuais no estilo do componente
  • As dimensões percentuais também requerem um elemento pai com o tamanho definido;
import React from 'react'; import {View} from 'react-native'; const PercentageDimensionsBasics = () => { return ( <View style={{height: '100%'}}> <View style={{ height: '10%', backgroundColor: 'powderblue', }} /> <View style={{ width: '66%', height: '90%', backgroundColor: 'skyblue', }} /> </View> ); }; export default PercentageDimensionsBasics;

3.3) Layout com Flexbox

  • Por padrão todos os componentes do React Native são flex e direcionados por coluna;
  • Na web o padrão é por linha (row), um ao lado do outro;
  • Já no React Native, o padrão é por coluna (column), um em baixo do outro;
    • display: flex
    • flexDirection: column
  • Para que um componente seja expandido e reduzido dinamicamente com base no espaço disponível podemos utilizar flex: 1;
⚠️
Um componente só pode expandir para preencher o espaço disponível se seu pai tiver dimensões maiores que 0.
  • Exemplo de layout com Flexbox:
import React from 'react'; import {View} from 'react-native'; const FlexDimensionsBasics = () => { return ( <View style={{flex: 1}}> <View style={{flex: 1, backgroundColor: 'powderblue'}} /> <View style={{flex: 2, backgroundColor: 'skyblue'}} /> <View style={{flex: 3, backgroundColor: 'steelblue'}} /> </View> ); }; export default FlexDimensionsBasics;
  • Todas as outras propriedades do Flexbox estão disponíveis no React Native:
    • Flex-Direction: column row columnReverse rowReverse
    • Layout-Direction: LTR RTL
    • Justify-Content: flexStart flexEnd center spaceBetween spaceAround spaceEvenly
    • Align-Items: stretch flex-start flex-end center baseline
    • Align-Self e Align-Content
    • Flex-Wrap, Flex-Basis, Grow e Shrink
    • Row-Gap, Column-Gap e Gap
    • Posição absoluta e relativa: relative absolute

3.4) Imagens

  • O React Native fornece uma maneira unificada de gerenciar imagens e outros ativos de mídia em seus aplicativos Android e iOS;

Imagens Estáticas

  • Para adicionar uma imagem estática, basta importar o componente Image
import {Image} from 'react-native';
  • Depois é só chamar o componente de imagem e inserir o caminho do arquivo:
<Image source={require('./src/assets/imagem.png')} />
Observações:
  • Podemos usar os sufixos @2x@3xpara fornecer imagens para diferentes densidades de tela.
└── img ├── check.png ├── check@2x.png └── check@3x.png
  • E chamar a imagem normalmente:
<Image source={require('./img/check.png')} />

Imagens na Rede

  • Também podemos exibir imagens que não estão no projeto
  • Porém, ao contrário dos recursos estáticos, precisamos especificar as dimensões da imagem;
// CORRETO <Image source={{uri: 'https://reactjs.org/logo-og.png'}} style={{width: 400, height: 400}} /> // ERRADO <Image source={{uri: 'https://reactjs.org/logo-og.png'}} />

Imagens de fundo (Background-Image)

  • Para exibir imagens de fundo podemos usar o componente <ImageBackground>;
  • Ele tem as mesmas propriedades que o componente <Image>
  • Exemplo simples:
<ImageBackground source={...} style={{width: '100%', height: '100%'}}> <Text>Inside</Text> </ImageBackground>
  • Exemplo completo com imagem na rede:
import React from 'react'; import {ImageBackground, StyleSheet, Text, View} from 'react-native'; const image = {uri: 'https://reactjs.org/logo-og.png'}; const App = () => ( <View style={styles.container}> <ImageBackground source={image} resizeMode="cover" style={styles.image}/> </View> ); const styles = StyleSheet.create({ container: { flex: 1, }, image: { flex: 1, justifyContent: 'center', }, }); export default App;

3.5) Cores

  • Os componentes no React Native são estilizados usando Javascript;
  • As propriedades de cores geralmente correspondem à forma como o CSS funciona na web;

Cores em Hexadecimal

  • É possível inserir cores conforme o padrão da web que é hexadecimal, como por exemplo:
    • #fafafa
    • #000000
    • #000 (abreviado)

Cores em RGB

  • React Native tem suporte para cores em rgb() e rgba()
    • '#f0f' (#rgb)
    • '#ff00ff' (#rrggbb)
    • '#f0ff' (#rgba)
    • '#ff00ff00' (#rrggbbaa)
    • 'rgb(255, 0, 255)'
    • 'rgb(255 0 255)'
    • 'rgba(255, 0, 255, 1.0)'
    • 'rgba(255 0 255 / 1.0)'

Cores Nomeadas

Cores em HSL

  • Também é possível usar hsl() e hsla():
    • 'hsl(360, 100%, 100%)'
    • 'hsl(360 100% 100%)'
    • 'hsla(360, 100%, 100%, 1.0)'
    • 'hsla(360 100% 100% / 1.0)'

Cores em Matriz (HWB)

  • React Native suporta hwb()em notação funcional:
    • 'hwb(0, 0%, 100%)'
    • 'hwb(360, 100%, 100%)'
    • 'hwb(0 0% 0%)'
    • 'hwb(70 50% 0%)'
 

4) Gestos e Toques

  • Com o React Native é possível lidar com todos os tipos de gestos comuns;

4.1) Botões

  • Um botão é um componente básico que é renderizado em todas as plataformas;

Botão simples

  • Um exemplo básico é o botão:
<Button onPress={() => { console.log('O botão foi pressionado!'); }} title="Toque aqui" color="#841584" />;

Componentes tocáveis (Touchables)

  • Os componentes "tocáveis" podem capturar gestos de toque e exibir feedback;
<TouchableHighlight onPress={() => { console.log('O botão foi pressionado!'); }} underlayColor="white"> <View> <Text>TouchableHighlight</Text> </View> </TouchableHighlight>;

4.2) Navegação entre telas

  • Aplicativos raramente são compostos de uma única tela.
  • No React Native, a forma mais simples de criar a navegação entre telas e guias é usando o React Natigation;

React Navigation

  • Primeiramente é preciso instalar a biblioteca:
npm install @react-navigation/native @react-navigation/native-stack

Dependências do React Navigation

  • Se for um projeto React Native simples, instale as dependências com npm:
npm install react-native-screens react-native-safe-area-context
  • Se for um projeto gerenciado pelo Expo, instale as dependências com expo:
npx expo install react-native-screens react-native-safe-area-context

Envolvendo a aplicação

  • Agora precisamos envolver todo o aplicativo com o NavigationContainer
  • Isso é feito no arquivo de entrada de nosso projeto, como index.jsou App.js:
import * as React from 'react'; import {NavigationContainer} from '@react-navigation/native'; const App = () => { return ( <NavigationContainer> {/* Restante da aplicação */} </NavigationContainer> ); }; export default App;

Criando as telas

  • Exemplo completo abaixo com 2 telas:
    • 1) Tela inicial (HomeScreen)
    • 2) Tela de perfil (ProfileScreen)
import * as React from 'react'; import {NavigationContainer} from '@react-navigation/native'; import {createNativeStackNavigator} from '@react-navigation/native-stack'; const Stack = createNativeStackNavigator(); const App = () => { return ( <NavigationContainer> <Stack.Navigator> <Stack.Screen name="Home" component={HomeScreen} options={{title: 'Welcome'}} /> <Stack.Screen name="Profile" component={ProfileScreen} options={{title: 'Profile'}} /> </Stack.Navigator> </NavigationContainer> ); }; export default App;

Navegando entre as telas

  • Cada tela <Stack.Screen> tem uma propriedade chamada: component;
  • A propriedade component é uma referência a um componente React;
  • Esses componentes recebem uma propriedade chamada navigation;
  • O navigation possui vários métodos para vincular a outras telas;

Componente HomeScreen.jsx

const HomeScreen = ({navigation}) => { return ( <Button title="Go to profile screen" onPress={() => navigation.navigate('Profile', {name: 'Jane'}) } /> ); };

Componente ProfileScreen.jsx

const ProfileScreen = ({navigation, route}) => { return ( <Text> This is {route.params.name}'s profile </Text> ); };
 

5) Observações Expo

  • Fluxos de trabalho no Expo
    • Managed Workflow (padrão, sem acesso as pastas Android e iOS)
    • Bare Workflow
    • Development Builds
      • Config Plugins
      • Custom Clients
Parar mudar um fluxo Managed Workflow para Bare Workflow basta rodar o comando:
npx expo prebuild
Configurar Build
Gerar APK