Next Level Week
Resumo dos últimos dias da NLW da Rocketseat.
Para o desenvolvimento mobile iremos utilizar a biblioteca expo, para criar o projeto mobile digite no PowerShell:
expo init mobile
E escolha a opção:
blank (TypeScript) same as blank but with TypeScript configuration
Quando criamos um projeto React Native que não seja pelo Expo, é possível iniciar um projeto React Native com Typescript, executando o comando:
npx react-native init authrn --template react-native-template-typescript
Com npx ele busca o pacote na web instala na sua máquina na versão mais atualizada, executa o comando react-native, deixa em cache por um tempo e depois desinstala, dessa forma você não precisa ficar com o react-native cli na node_modules principal da sua máquina. O template Typescript vem da flag: –template react-native-template-typescript. Porém a estrutura do projeto e as estratégias do desenvolvimento da aplicação diferem.
Repare principalmente que o projeto expo não tem as pasta android e ios. No projeto criado pelo npm, ao querer depurar o app pelo emulador é necessário, para instalação do app no emulador, emitir o comando:
npx react-native run-android
Como no projeto expo não existe a pasta android, acontece o seguinte erro:
error Android project not found. Are you sure this is a React Native project? If your Android files are located in a non-standard location (e.g. not inside 'android' folder), consider setting `project.android.sourceDir` option to point to a new location. Run CLI with --verbose flag for more details.
Ao pesquisar na Internet sobre o problema vai levar a vários tópicos que vão indicar para atualizar o react-native, o que vai levar a outra sucessão de erros:
No projeto Expo, que faz a interface com o navegador é o Metro Builder pelo navegador, e é ele que oferece as opções de depuração da aplicação. Porém para dispositivos físicos, aparentemente, não diferenças no desenvolvimento.
Dentro da pasta do projeto digite:
yarn add expo OU npm install expo
Depois digite:
yarn start OU npm start
Que vai abrir o browser para visualizar os logs da aplicação, quais celulares disponíveis estão debugando, etc.
Quais celulares disponíveis estão debugando, etc.
Para listar emuladores podemos aplicar o comando:
emulator –list-avds
E para iniciar um emulador:
emulator –avd Nome_Emulador
O importante é o endereço abaixo que permite testarmos a aplicação:
exp://192.168.0.101:19000
Para testar com o QR Code temos que instalar o app Expo cliente no celular:
To run the app with live reloading, choose one of:
-Scan the QR code above with the Expo app (Android) or the Camera app (iOS).
-Press a for Android emulator, or w to run on web.
-Press e to send a link to your phone with email.
-Press s to sign in and enable more options.
Com este QR Code é possível passar para outras pessoas com o expo instalado para poderem avaliar seu aplicativo pronto:
Para testar no emulador podemos ver o vídeo do link antes pra saber como instalar para React Native: emulando-react-native-no-iosandroid-com-expo
O expo pode dar muitos problemas de configuração, tem limitações de proxy e Firewall, mas dá pra consultar alguns deles em: expo-common-issues
Como podemos ver a estrutura do programa mobile e igual a da Web: JSX (Javascript + XML) e funções retornando Elementos gráficos com componentes utilizando os estados e propiedades. Porém estes elementos não são HTML puro e sim componentes pré-criados pela biblioteca do Native (StyleSheet, Text, View) e todos elementos tem display flex por padrão. O css também não existe (classes, ids) e nem herança de estilos. Cria-se um estilo particular e identificado por elemento. Não há parte de animações, nem gradientes, grid tem que fazer na unha.
A única exceção de herança de estilo é quando se coloca componentes Text aninhados como abaico:
Por padrão, o Native também não lê arquivos de imagem svg só png. Teria que instalar uma extensão. No mobile tem o conceito de densidade de pixels e temos que exportar as imagens em 3 tamanhos que o Native reconhece a resolução pelo nome …2x, 3x, etc. Antes de existir o React, não era possível o Javascript reconhecer imagens. Para fazer a aplicação reconhecer arquivos png precisamos criar uma pasta @type em src com um arquivo index.d.ts com a seguinte declaração: declare module ‘*.png’;
Crie uma pasta src e dentro dela a pasta pages. Dentro dessa pasta teremos as páginas igual o que foi feito na aplicação web. Comece criando a página/pasta Landing com os arquivos index.tsx e styles,ts (não mais css)
No arquivo principal App.tsx vamos prepara-lo para receber o componente Landing. Como não é possível “empilhar” os companentes Landing e StatusBar sem que haja alg envelopando-os, aqui podemos fazer de duas formas principais:
A vantagem do Fragment é que não irá renderizar mais uma View, pois de Landing já está retornando outra View.
Para instalar as fontes usadas no projeto Web (Archivo e Poppins) faça o seguinte comando:
expo install @expo-google-fonts/archivo @expo-google-fonts/poppins
Após feito isso, na página App.tsx importe as fontes e o módulo AppLoading:
import { AppLoading } from 'expo'
import { Archivo_400Regular, Archivo_700Bold, useFonts } from '@expo-google-fonts/archivo'
import { Poppins_400Regular, Poppins_600SemiBold } from '@expo-google-fonts/poppins'
Na mesma página, declare globalmente as variáveis e faça um condicional para verificar se as fontes foram carregadas:
Por fim, é so utilizar nas StyleSheets de qualquer página.
Inicialmente, para criar os botões podemos utilizar o TouchableOpacity, importando do React Native.
import {View, Image, Text, TouchableOpacity} from 'react-native'
E aplicando nos botões ficaria como abaixo. Repare que o style recebe um array de estilos, permitindo 2 estilos aproveitarem um estilo básico simulando a flexibilização de uma herança.
Para navegar vamos instalar a biblioteca React Native digitando:
yarn add @react-navigation/native OU npm install @react-navigation/native
Depois temos que instalar as dependências em relação ao expo:
expo install react-native-gesture-handler react-native-reanimated react-native-screens react-native-safe-area-context @react-native-community/masked-view
A 3 tipos principais de navegação React:
Precisamos instalar então a navegação stack e bottomtabs:
yarn add @react-navigation/stack OU npm install @react-navigation/stack
yarn add @react-navigation/bottom-tabs
Criamos então uma pasta routes dentro de src e criamos duas páginas AppStack.tsx e StudyTabs.tsx uma pra cada tipo de navegação. A AppStack.tsx conterá as chamadas das páginas sem Tabs Landing e GiveClasses e a página com as Tabs StudyTabs. E por fim, nosso AppStack tem retornar um NavigationContainer contendo as telas(Screen) conforme a documentação.
A StudyTabs terá o direcionamento para duas páginas TeacherList (aba Proffys) e Favoritos. Na StudyTabs conterá o conteúdo e o visual (style.ts) das tabs.
Repare no módulo Ionicons que traz umas biblioteca de ícones padrão para celular. ionicons
Poderia ter sido utilizado o icons do: feathericons
Qualquer deles pode ser acessado pela biblioteca do expo:
import { Ionicons } from '@expo/vector-icons'
import { Feather } from '@expo/vector-icons';
<Ionicons name="ios-easel" size={20} color= '#fff'/>
<Feather name="filter" size={20} color="#fff" />
E que a estilização do tab tem ser feita pela propriedade tabBarOptions do Navigator
As duas páginas devem conter conteúdo similar que irá ter o conteúdo (index.tsx) e o visual (style.ts) das páginas.
Com isso, já podemos navegar. Na página Landing import useNavigation da React Navigation:
import { useNavigation } from '@react-navigation/native'
Crie as funções que serão associando aos botões de navegação e indique a rota:
Finalmente, atribua os métodos aos botões.
Precisamos instalar novamente a biblioteca que facilita o consumo de API externas pela aplicação: yarn add axios
Como no projeto Web, crie uma pasta services e dentro dela o arquivo api.ts.
O IP que utilizamos é o disponibilizado pelo Metro Bundler abaixo que permite testarmos a aplicação. Lembre-se que sempre que trocar de máquina, deve-se atualizar este número para testar na máquina atual.
192.168.0.101:3333
Isso é necessário pois o localhost pode não ser acessível na rede, então é necessário utilizar o IP. Em um terminal paralelo, navegue até a pasta do servidor e inicie-o com o comando yarn start. Depois teste com o Insomnia a conexão:
A chamada da API na aplicação mobile é idêntica a da web.
Já nos componentes de filtro da página TeacherList, uma diferença é que invés de Onchange está se usando OnchangeText, mas isso porque, por razões de tempo, não foi implementado a caixa de seleção (ficando como um dos Desafios mais adiante).
Para testar o botão de filtro é possível fazer a mesma estratégia de emitir um console.log no método relacionado:
Única coisa a se lembrar é de trocar o aparelho que estiver se testando, se for emulador ou aparelho físico.
Feito isso o método é idêntico ao do projeto web:
No botão do WhatsApp vamos aplicar uma técnica conhecida como “Deep Linking” onde uma aplicação abre outra aplicação. Grande parte de aplicação mobile tem um endereço URL em que é possível acessar pelo módulo do React Native Linking:
import { View, Image, Text, Linking, AsyncStorage } from 'react-native';
Para armazenamento interno no mobile precisamos instalar um DB pelo:
expo install @react-native-community/async-storage
Temos que criar a propriedade no componente TeacherItem para sabermos quando foi favoritado e fazer as mudanças necessárias no Layout.
O favoriteArray.push adiciona o item no Array de favorito, o splice remove o conteúdo da lista. No botão dos favoritos há apenas um condicional trocando a imagem do botão favorito:
Na página TeacherList precisamos de uma variável constante de estado, para acompanhar as mudança no controle salvando a id do professor.
const [favorites, setFavorites] = useState<number[]>([]);