introdução ao react native · introdução ao react native antonio lopes jr react native, 1ª...

116
––– Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

Upload: others

Post on 09-Aug-2020

25 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

–––

Introdução ao React Native

Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

Page 2: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

1

Sumário 1 Introdução .................................................................................................................3

1.1 Pré-requisitos ....................................................................................................4

2 Ambiente de Desenvolvimento..................................................................................5

2.1 Windows ...........................................................................................................5

2.1.1 Chocolatey ................................................................................................5

2.1.2 JDK ...........................................................................................................6

2.1.3 Android Studio ..........................................................................................6

2.1.4 Criando Emulador no Android ..................................................................9

2.1.5 Python ....................................................................................................13

2.1.6 Node JS e Node Package Manager .......................................................13

2.1.7 React Native CLI ....................................................................................14

2.1.8 Visual Studio Code .................................................................................14

2.1.9 Variáveis de Ambiente ............................................................................16

2.1.10 Testando o Ambiente de Desenvolvimento ............................................19

2.2 Linux ...............................................................................................................21

2.3 Mac OS ...........................................................................................................21

3 Todo List Manager ..................................................................................................22

3.1 Iniciando o Projeto ToDoManager ..................................................................24

3.2 Styles ..............................................................................................................28

3.3 Layout e Flexbox .............................................................................................30

3.4 Tela de Login ..................................................................................................34

3.5 Props e State ..................................................................................................39

3.6 Tela de Registro ..............................................................................................43

3.7 Navegação entre Telas ...................................................................................48

Page 3: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

2

3.8 Integração com o Firebase .............................................................................56

3.9 Registrando Usuário .......................................................................................57

3.10 Autenticando Usuário ......................................................................................63

3.11 Tela de Listagem.............................................................................................68

3.12 Verificando o Estado do Usuário .....................................................................77

3.13 Tela de Tarefa .................................................................................................83

3.14 Componente de Listagem ...............................................................................94

3.15 Ajustando a Listagem Done .......................................................................... 103

3.16 Atualizando uma Tarefa ................................................................................ 105

4 Referências Bibliográficas ..................................................................................... 115

Page 4: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

3

1 INTRODUÇÃO

Quando mencionamos desenvolvimento de aplicações para dispositivos

móveis sabemos do grande desafio de disponibilizar essas aplicações nas plataformas

Android e iOS. Existem várias abordagens disponíveis para utilizarmos no

desenvolvimento de aplicativos para dispositivos móveis tais como a abordagem de

construção de aplicativos nativos, construção de aplicativos webs ou aplicativos híbridos

e construção de aplicativos multiplataforma. Cada abordagem tem suas vantagens e

desvantagens.

Se utilizarmos uma abordagem de construção de aplicativos nativos,

utilizando as linguagens Java ou Kotlin para Android e Objective-C ou Swift para iOS,

o maior desafio fica por conta do time de desenvolvedores. Essa abordagem requer um

time especialista para construção da nossa aplicação para Android e outro time

especialista responsável pela construção de nosso aplicativo para iOS o que acaba

elevando o custo de desenvolvimento, mas provendo uma experiência mais consistente

ao usuário.

Se utilizarmos uma abordagem de construção de aplicativo web, onde

utilizamos uma linguagem padrão web para geração de conteúdo, não necessitamos de

especialistas em construção de aplicativos para dispositivos móveis, mas de

conhecimento básico em desenvolvimento de cada plataforma. A construção de nossa

aplicação é única e reaproveitamos o código fonte construído para ambas as plataformas,

pois o código fonte roda em um browser. O principal desafio dessa abordagem é

proporcionar uma experiência agradável ao usuário, mas por outro lado, diminuímos o

custo de um time com especialistas em cada plataforma.

A abordagem de construção de aplicativos multiplataforma, que é a

abordagem que vamos utilizar, tem como principio codificar uma única vez utilizando

uma única linguagem e gerar aplicações nativas para Android e iOS. Essa abordagem

é uma combinação das duas abordagens mencionadas anteriormente e também

apresenta desafios que vamos entender melhor durante a leitura da apostila.

Page 5: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

4

1.1 PRÉ-REQUISITOS

Embora não seja imprescindível, conhecimento em Javascript é bem-vindo.

Mas os conceitos mais importantes para aproveitarmos bem o conteúdo que iremos

estudar são:

1. Conhecimento em linguagem orientada a objeto;

2. Conhecimento básico em desenvolvimento para Android com Java ou

Kotlin;

3. Conhecimento básico em desenvolvimento para iOS com Objective-C ou

Swift.

Além dos conceitos das linguagens, nós também precisamos nos certificar de

que temos instalados o Java Development Kit (JDK), Android Studio e XCode (no

caso do Mac OS). Essas ferramentas nos ajudarão a compilar nossas aplicações para

as plataformas Android e iOS. Mas faremos isso no próximo capítulo.

Page 6: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

5

2 AMBIENTE DE DESENVOLVIMENTO

O React Native é um framework cujo o ambiente de desenvolvimento é

multiplataforma, ou seja, conseguimos instalar o React Native no sistema operacional

Windows, Linux ou Mac OS. Ao final desse capítulo devemos estar aptos a preparar o

ambiente de desenvolvimento do React Native nas plataformas Windows, Linux e Mac

OS.

2.1 WINDOWS

No Windows precisamos instalar o Chocolatey, Java Development Kit, Android Studio, Python, Node JS, Node Package Management (NPM), React Native Command Line Interface (CLI) e Visual Studio Code. Vamos a instalação de cada

uma dessas ferramentas.

2.1.1 Chocolatey

O Chocolatey é um software que ajuda a automatizar processos. Esses

processos são escritos através de scripts. Não iremos construir scripts, mas vamos

executar scripts prontos para instalar os softwares que usaremos em nosso ambiente de

desenvolvimento.

1. Vamos executar o PowerShell em modo administrador;

2. Temos que alterar as políticas de execução de scripts do PowerShell. Vamos executar o comando Set-ExecutionPolicy Bypass -Scope

Process -Force. O PowerShell nos apresentará uma mensagem de

confirmação. Vamos digitar A e pressionar a tecla enter;

Figura 2.1 - Alteração da Política de Execução

Page 7: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

6

3. Agora, vamos executar o comando iex ((New-Object

System.Net.WebClient).DownloadString(‘https://chocolat

ey.org/install.ps1’)) para instalar o Chocolatey.

Pronto! Agora a instalação de algumas ferramentas ficará bem mais fácil.

2.1.2 JDK

Como iremos utilizar o ambiente de desenvolvimento para Android, também

precisaremos do JDK. Vamos instalar o JDK pelo Chocolatey.

1. Vamos executar o PowerShell em modo administrador;

2. Agora basta executar o comando choco install -y jdk8.

Fácil assim! Instalando o JDK pelo Chocolatey fica fácil. E ainda, o script de

instalação executado através do Chocolatey configura a variável de ambiente

JAVA_HOME. Menos um item a se preocupar.

2.1.3 Android Studio

Vamos abordar duas formas de instalar o Android Studio: através do

Chocolatey e a forma manual.

Instalar o Android Studio utilizando o Chocolatey é simples.

1. Vamos executar o PowerShell em modo administrador;

2. Vamos executar o comando choco install -y androidstudio.

Assim como ocorre durante a instalação do JDK, o script de instalação do

Android Studio executa alguns passos adicionais, isto é, antes de instalar o Android Studio o script instala o SDK do Android Studio, configura a variável de ambiente

ANDROID_HOME indicando o diretório que o SDK foi instalado e adiciona na variável

de ambiente PATH dois diretórios: ANDROID_HOME\tools e

ANDROID_HOME\plataform-tools.

Instalar o Android Studio manualmente requer executar, também

manualmente, alguns passos adicionais, ou seja, instalar o SDK e configurar as variáveis

de ambiente. Reservaremos um subcapítulo específico para configurarmos as variáveis

de ambiente. Vamos focar na instalação do Android Studio e SDK.

Page 8: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

7

1. Vamos abrir um navegador e digitar o endereço

https://developer.android.com/studio/;

2. Vamos clicar no botão “Download Android Studio”;

Figura 2.2 - Downloading Android Studio

3. Na sequência, uma janela será apresentada. Vamos marcar a opção “I have read and agree with the above terms and conditions” e clicar no

botão “Download Android Studio for Windows”;

4. Salvaremos o arquivo instalador do Android Studio na pasta downloads;

5. Vamos aguardar a finalização do download, localizar o arquivo instalador

do Android Studio na pasta de downloads e clicar duas vezes sobre o

mesmo;

6. Vamos clicar no botão “Next”, “Next” outra vez, “Next” mais uma vez e

vamos clicar no botão “Install”;

7. Ao finalizar a instalação, vamos marcar a opção “Start Android Studio”

e clicar no botão “Finish”;

Page 9: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

8

Figura 2.3 - Executando o Android Studio.

8. A primeira vez que executarmos o Android Studio uma janela com o título

“Complete Installation” será apresentada. Vamos marcar a opção “Do not import settings” e clicar no botão “Ok”;

Figura 2.4 - Completando a instalação do Android Studio.

9. Na próxima janela, com o subtítulo “Welcome Android Studio” vamos

clicar no botão “Next”;

10. Desta vez, na janela com o subtítulo “Install Type” vamos selecionar a

opção “Stardard” e clicar no botão “Next”;

11. Vamos selecionar o tema e clicar no botão “Next” novamente. Eu gosto

do tema dark, mas podemos escolher qualquer tema;

12. Na janela com o subtítulo “Verify Settings” vamos clicar no botão

“Finish”. Esse passo vai demorar um pouco para finalizar;

Page 10: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

9

13. Se tudo ocorrer como esperado, no final da instalação, uma janela com a

mensagem “Deseja permitir que este aplicativo faça alterações no seu dispositivo?” será apresentada. Vamos clicar no botão “Sim”;

14. Por último, vamos clicar no botão “Finish”.

Pronto! Android Studio e SDK instalados manualmente.

2.1.4 Criando Emulador no Android

Durante o desenvolvimento de nosso aplicativo temos que fazer o teste.

Podemos testar em um dispositivo físico com Android ou criar um emulador. Testar

nosso aplicativo no emulador é um cenário que nos atente muito bem. Então, vamos aos

passos para criar um emulador.

1. Vamos abrir o Android Studio; 2. Na janela com o título “Welcome to Android Studio” vamos selecionar a

opção “Start a new Android Studio project”;

Figura 2.5 - Criando projeto no Android Studio.

3. Nas próximas quatro telas vamos clicar, respectivamente, nos botões

“Next”, “Next”, “Next” novamente e, por último, vamos clicar no botão

“Finish”. Esse passo vai demorar um pouco, então, vamos aguardar até

que o Android Studio conclua;

4. Em seguida, vamos clicar no menu “Tools => AVD Manager” ou clicar no

ícone do AVD Manager localizado no canto superior direito do Android

Page 11: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

10

Studio. Observe o destaque em vermelho da Figura 2.6 - Ícone do AVD

Manager.;

Figura 2.6 - Ícone do AVD Manager.

5. Uma janela com o título “Android Virtual Device Manager” será

apresentada. Vamos clicar no botão “Create Virtual Device”;

Figura 2.7 - Criando Virtual Device

6. Na lista Category localizada ao lado esquerdo, vamos selecionar Phone e na lista central, vamos selecionar Nexus 5 e clicar no botão “Next”;

Page 12: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

11

Figura 2.8 - Selecionando o tipo do emulador

7. Na próxima janela, vamos escolher a versão do Android que iremos

configurar no emulador. Vamos selecionar “Nougat API Level 24” e clicar

no botão “Next”. Observe que existe a palavra download a frente do nome

Nougat. Isso quer dizer que vamos realizar o download da versão do

Android e que vai demorar um pouco;

8. Ao finalizar, vamos clicar no botão “Finish”; 9. Vamos selecionar “Nougat API Level 24” e clicar no botão “Next”;

Page 13: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

12

Figura 2.9 - Finalizando a configuração do emulador

10. E por último, vamos clicar no botão “Finish”.

Finalizada a configuração do nosso emulador. Se tudo ocorrer como esperado,

veremos o nosso emulador criado na lista “Your Virtual Devices”. Observe a Figura

2.10 - Your Virtual Devices.

No subcapítulo Testando o Ambiente de Desenvolvimento vamos verificar se

o nosso emulador está funcionando corretamente.

Page 14: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

13

Figura 2.10 - Your Virtual Devices

2.1.5 Python

Python é uma linguagem de programação que o React Native utiliza para

transformar os códigos JavaScript Extension (JSX) em JavaScript. Não iremos utilizar

diretamente o Python, mas não devemos nos preocupar com isso, pois o React Native

cuidará dessa conversão para nós. Então, vamos a instalação.

1. Vamos executar o PowerShell em modo administrador;

2. Em seguida, vamos executar o comando choco install -y python.

Pronto! Agora iremos instalar o Node JS.

2.1.6 Node JS e Node Package Manager

Assim como o Python, o Node JS também é uma linguagem de programação.

O Node JS é um framework que fornece interfaces (API) entre a linguagem de

programação JavaScript e o sistema operacional. É o Node JS que interpreta os

códigos JavaScripts de nossa aplicação para executá-los. Junto com o instalador do

Node JS existe o Node Package Manager (NPM). O NPM é o gerenciado de bibliotecas

ou pacotes do Node JS. Mas não vamos nos preocupar com o NPM, pois o processo de

instalação do Node JS já instala o NPM.

Vamos aos passos da instalação do Node JS.

Page 15: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

14

1. Vamos executar o PowerShell em modo administrador;

2. Em seguida, vamos executar o comando choco install -y nodejs.

Pronto! Node JS e NPM instalados. Para testar se a instalação procedeu com

sucesso, vamos abrir o prompt de comando e digitar o comando node -v. Esse

procedimento deve informar a versão do Node JS instalada. Vamos também digitar o

comando npm -v. Esse procedimento deve informar a versão do NPM instalada.

2.1.7 React Native CLI

Falta pouco para termos o nosso ambiente pronto para rodar em Windows. A

penúltima ferramenta que iremos instalar é o React Native Command Line Interface.

O React Native CLI é uma ferramenta de linha de comando que nos auxiliará na criação

dos projetos React Native e execução dos aplicativos nos emuladores e dispositivos,

entre outros comandos.

1. Vamos executar o PowerShell em modo administrador;

2. Vamos executar o comando npm install –g react-native-cli e

aguardar a finalização da instalação.

Pronto! Vamos agora instalar o Visual Studio Code.

2.1.8 Visual Studio Code

O Visual Studio Code (VS Code) é a ferramenta de interface que utilizaremos

para codificar nosso aplicativo com React Native. Vamos aos passos dessa instalação.

1. Vamos acessar o site https://code.visualstudio.com e clicar na opção de

Download for Windows. Vamos salvar o instalador na pasta download;

2. Vamos localizar o instalador do Visal Studio Code na pasta download e

clicar duas vezes para iniciar a instalação;

3. Na janela que abrirá após o passo descrito no item 2, vamos clicar no botão

“OK”;

Page 16: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

15

Figura 2.11 [Inicializando a instalação do Visual Studio Code]

4. Na sequência, vamos clicar no botão “Next”;

5. Na tela seguinte, temos que aceitar os termos de licença, selecionando a

opção “I accept the agreement” e clicar no botão “Next”;

Figura 2.12 [Aceitando os termos da licença]

6. Vamos manter a pasta indicada para instalar o “Visual Studio Code”

clicando no botão “Next” novamente;

7. Vamos clicar no botão “Next” nas duas próximas janelas e, na sequência,

vamos clicar no botão “Install”;

8. Para finalizar a instalação, vamos desmarcar a opção “Launch Visual Studio Code” e clicar no botão “Finish”.

Figura 2.13 [Finalizando a instalação do Visual Studio Code]

Page 17: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

16

Pronto! Mais uma ferramenta instalada.

2.1.9 Variáveis de Ambiente

Precisamos configurar duas variáveis de sistema para testarmos o nosso

ambiente de desenvolvimento. As variáveis são JAVA_HOME e Path. Na variável

JAVA_HOME iremos mapear o caminho do Java Development Kit (JDK) para ser

utilizado no processo de compilação do Android. Na variável Path iremos mapear o

caminho do Android Debug Bridge (ADB) para nos ajudar no processo de deploy e

debug do Android. Vamos começar configurando a variável JAVA_HOME.

1. Pressione a tecla Windows e digite Sistema;

2. Na lista, vamos clicar na opção Sistema;

Figura 2.14 [Localizando Configurações de Sistemas]

3. Na sequência, nas configurações do Sistema, no menu a esquerda,

vamos selecionar a opção “Configurações Avançadas do Sistema”;

Figura 2.15 [Configurações Avançadas do Sistema]

Page 18: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

17

4. Na janela apresentada a seguir, vamos clicar no botão “Variáveis de Ambiente”;

Figura 2.16 [Variáveis de Ambiente]

5. Agora, vamos clicar no botão “Novo”. No entanto, existem dois botões

“Novo”. Vamos clicar no botão “Novo” localizado na parte inferior;

6. Na janela apresentada na sequência, no campo “Nome da variável”, vamos digitar “JAVA_HOME”. No campo “Valor da variável” vamos

localizar a pasta onde está instalada a JDK e clicar no botão “OK”. No

meu caso esta pasta está localizada em c:\Program

Files\Java\jdk1.8.0_144;

Page 19: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

18

Figura 2.17 [Variável JAVA_HOME]

7. O próximo passo é clicar no botão “Editar”. No entanto, existem dois

botões “Editar”. Vamos clicar no botão “Editar” localizado na parte

superior;

8. Na próxima janela apresentada, vamos clicar no botão “Novo” e na

sequência, vamos clicar no botão “Procurar”;

Figura 2.18 [Editando a variável Path]

9. No caminho do diretório, temos que localizar a pasta “platform-tools”

dentro da pasta do SDK do Android. No meu caso esta pasta está

localizada em “c:\Users\Hannibal\AppData\Loca\Android\sdk\platform-tools”;

10. Vamos repetir os passos 7 e 8, mas desta vez para configurar a pasta

“tools”;

11. Por último, vamos fechar as janelas clicando nos botões “OK”.

Pronto! Vamos testar nosso ambiente.

Page 20: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

19

2.1.10 Testando o Ambiente de Desenvolvimento

Agora é a hora de cruzar os dedos. Vamos testar nosso ambiente de

desenvolvimento. Vamos dividir o teste do nosso ambiente em três passos: abrir o

emulador; criar um projeto em React Native; compilar e executar o projeto no emulador.

2.1.10.1 Abrir o emulador

Para facilitar o desenvolvimento do nosso aplicativo vamos abri o emulador

do Android através de linha de comando. Esse procedimento é bem simples.

1. Vamos abrir o Power Shell em modo administrador;

2. Em seguida, vamos executar o comando emulator -list-avds;

3. Uma listagem será apresentada. Se seguimos os passos descritos no

subcapítulo Criando Emulador no Android um dos itens listados deve ser

“Nexus_5_API_24”; 4. Por último, vamos executar o comando emulator -avd

Nexus_5_API_24.

Pronto! Agora é só aguardar alguns instantes que veremos nosso emulador

pronto para ser utilizado.

2.1.10.2 Criando um Projeto

Para criar um projeto em React Native iremos utilizar o comando react-

native init, que é um comando reconhecido pelo React Native CLI para criar um

projeto inicial. Vamos ao passo-a-passo.

1. Vamos abrir outra instância do Power Shell em modo administrador;

2. Em seguida, vamos navegar até a nossa pasta de projetos React Native.

No meu caso, minha pasta de projetos fica em

c:\Users\Hannibal\ReactNative;

Figura 2.19 – Criando projeto incial React Native

Page 21: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

20

3. Na sequência, vamos executar o comando react-native init

HelloWorld.

Pronto! É só aguardar que um projeto React Native com o nome HelloWorld

será criado.

2.1.10.3 Compilando e executando o projeto

Falta pouco! Vamos aos últimos passos para compilarmos nosso projeto

HelloWorld e testarmos no emulador.

1. Na mesma instância do Power Shell que utilizamos no subcapítulo

anterior vamos entrar na pasta do projeto HelloWorld executando o

comando cd HelloWorld. Temos que certificar que o emulador do

Android esteja aberto;

2. Na sequência, vamos executar o comando react-native run-

android e aguardar até que esse procedimento finalize.

Ufa! Após todos esses passos devemos ter o projeto HelloWorld do Android

sendo executado no emulador. Vamos observar a Figura 2.20 – Projeto HelloWorld

executando no emulador

Figura 2.20 – Projeto HelloWorld executando no emulador

Page 22: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

21

2.2 LINUX

No Linux precisamos instalar o Java Development Kit, Android Studio, Node JS, Node Package Management (NPM), React Native Command Line Interface (CLI) e Visual Studio Code. Vamos a instalação de cada uma dessas ferramentas.

2.3 MAC OS

No Mac OS precisamos instalar o Java Development Kit, Android Studio, XCode, Homebrew, Node JS, Node Package Management (NPM), React Native Command Line Interface (CLI) e Visual Studio Code. Vamos a instalação de cada

uma dessas ferramentas.

Page 23: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

22

3 TODO LIST MANAGER

Agora que temos nosso ambiente de desenvolvimento pronto, podemos

dedicar um tempo para descrever as principais funcionalidades do nosso aplicativo de

gerenciamento de tarefas.

Teremos quatro telas em nosso aplicativo. Visto pela quantidade de telas

nosso aplicativo parece ser simples, mas iremos explorar vários recursos que o

framework React Native fornece.

A Figura 3.1 – Autenticação com o Firebase

é o protótipo de nossa tela de autenticação com o

Firebase. Embora seja uma tela bem simples, a regra

por trás da tela não é tão simples.

• O usuário digita o e-mail e senha e ao

clicar no botão Sign In, o aplicativo

realiza a autenticação junto ao Firebase;

• Caso o usuário já tenha se cadastrado

anteriormente e digitou os dados

corretamente, a autenticação é realizada

com sucesso e a aplicação redireciona

para a tela de listagem de tarefas;

• Caso o usuário não tenha se cadastrado

anteriormente, a aplicação

disponibilizará a funcionalidade de se

registrar clicando no texto em negrito Register;

• Uma vez que o usuário se autenticou, a aplicação não irá pedir ao mesmo

que se autentique novamente toda vez que inicializar o aplicativo, ou seja,

a aplicação não apresentará a tela de autenticação e redirecionará para a

tela com as tarefas.

Figura 3.1 – Autenticação com o Firebase

Page 24: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

23

A Figura 3.2 – Registro de Usuário é o protótipo de nossa tela de registrar

usuário. Essa tela é bem semelhante a tela apresentada

na Figura 3.1 – Autenticação com o Firebase. Vamos

detalhar as características da tela de registro.

• O usuário digita o e-mail e senha e ao clicar no

botão Register User, o aplicativo realiza o registro de

um novo usuário no Firebase;

• Caso o usuário já tenha se cadastrado

anteriormente e digitou os dados corretamente, uma

mensagem de alerta será apresentada informando que

o usuário já está cadastrado;

A Figura 3.3 – Lista de Tarefas é o protótipo

de nossa tela de tarefas. Vamos detalhar as

características da tela de tarefas.

• Na tela de tarefas nós teremos duas abas: To Do e Done;

• Na aba To Do teremos uma listagem com

as tarefas a serem realizadas. Essas

tarefas serão subdivididas em duas

sessões: Hight Priority e Low Priority;

• Na aba Done teremos uma listagem com

as tarefas realizadas;

• Todas as tarefas estarão armazenadas no

Firebase. Então, nossa aplicação será

responsável em buscar essas tarefas no

Firebase e preencher as listagens;

• Cada tarefa da listagem To Do será

composta por um componente que iremos

reutilizá-lo na listagem Done;

Figura 3.2 – Registro de Usuário

Figura 3.3 – Lista de Tarefas

Page 25: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

24

• Ao clicar na tarefa, a aplicação deve navegar para a tela com os detalhes

da tarefa;

• O botão representado pelo sinal de mais, ao ser clicado, a aplicação

navegará para a tela de criação de tarefa.

Nosso último protótipo é representado pela Figura 3.4 – Criação e Detalhes

da Tarefa.

• Na tela representada pela Figura 3.4 –

Criação e Detalhes da Tarefa tem como

responsabilidade tanto criar tarefas

quanto atualizar;

• Vamos realizar a validação dos campos

“Title” e “Resume”. Ambos não podem

ser vazios;

• Na criação de uma tarefa, o Switcher “High Priority” deverá ser apresentado

marcado. O Switcher “Is Done?” deverá

ser apresentado desmarcado;

• A aplicação deverá armazenar os dados

da tarefa no Firebase.

3.1 INICIANDO O PROJETO TODOMANAGER

Vamos iniciar e configurar a estrutura básica

do nosso projeto. A configuração básica consiste em organizar o nosso código fonte em

uma estrutura mais organizada e configurar a inicialização do nosso aplicativo para

considerar uma implementação única, ou seja, o mesmo código para Android e iOS.

1. Vamos abrir o Terminal no MacOS ou, se o sistema operacional for

Windows, vamos abrir o PowerShell; 2. Precisamos navegar dentro da pasta onde normalmente criamos nossos

projetos, por exemplo, ../User/Documents/Projects;

Figura 3.4 – Criação e Detalhes da Tarefa

Page 26: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

25

3. Agora, vamos digitar a linha de comando react-native init

ToDoManager e pressionar a tecla Enter;

Este procedimento pode levar alguns minutos. Vamos aguardar!

4. Vamos abrir a pasta do nosso projeto no Visual Studio Code. No VS Code

clique no menu “File => Open” e selecione a pasta do projeto

ToDoManager que acabamos de criar;

Figura 3.5 – Abrindo a pasta do projeto no VS Code

5. Com o objetivo de organizar a estrutura do nosso projeto, vamos criar

algumas pastas. Na raiz do projeto, vamos criar a pasta “src”;

6. Dentro da pasta “src”, vamos criar mais cinco pastas: assets,

components, routes, screens e services. Ao final, devemos ter uma

estrutura semelhante a Figura 3.6 – Estrutura do projeto;

Figura 3.6 – Estrutura do projeto

Até agora, temos o nosso projeto criado e estruturado. Vamos codificar um

pouquinho.

7. Vamos mover o arquivo App.js para dentro da pasta “src/screens”;

Page 27: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

26

8. Agora, vamos abrir o arquivo index.js e atualizar o import da classe App

de acordo com o código disponível na Tabela 3.1 – Ajustando os imports

do arquivo index.js;

JavaScript import { AppRegistry } from 'react-native'; import App from './src/screens/App'; import { name as appName } from './app.json'; AppRegistry.registerComponent(appName, () => App);

Tabela 3.1 – Ajustando os imports do arquivo index.js

Temos dois pontos importantes no código da Tabela 3.1 – Ajustando os

imports do arquivo index.js. O primeiro é que utilizamos o import para referenciar a

classe App que movemos anteriormente. O segundo é que registramos a classe App no

AppRegistry como sendo a classe inicial da nossa aplicação. A API AppRegistry informa ao React Native qual é o componente inicial de nossa aplicação.

Falta pouco para finalizarmos a configuração inicial de nosso projeto. Vamos

compilar e instalar nosso projeto nos emuladores do Android e iPhone.

9. Vamos abrir o terminal dentro do VS Code. Clique no menu “View => Integrated Terminal”;

Figura 3.7 – Abrindo integrated terminal

Este passo abrirá uma visão do terminal dentro do VS Code. Com isso,

podemos executar os comandos pelo próprio VS Code.

Page 28: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

27

Tabela 3.2 – Terminal integrado com o VS Code

10. Vamos executar o comando react-native run-ios e pressionar a

tecla Enter; 11. Ao finalizar o comando executado no item anterior, vamos executar outro

comando, desta vez o comando é react-native run-android. Não

podemos esquecer de abrir o emulador do Android. Podemos revisar esse

procedimento no subcapítulo Abrir o emulador.

Pronto! Neste momento, temos que ter o nosso projeto rodando nos

emuladores do Android e iPhone. Observe as figuras abaixo.

Figura 3.8 – Componente App no iPone

Figura 3.9 – Componente App no Android

Page 29: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

28

3.2 STYLES

A definição de estilos em um componente em React Native é bem semelhante

a definição de estilos proposta pelo Cascading Style Sheets (CSS) na web. Todo

Component ou classe que herda Component possui a propriedade style. Os nomes e

valores dos estilos, normalmente correspondem à mesma forma como o CSS funciona

na Web, exceto que os nomes são escritos em minúsculos e sem hífen como, por

exemplo, backgroundColor ao invés de background-color.

Vamos a um exemplo.

1. Vamos abrir o arquivo App.js localizado dentro da pasta src; 2. Vamos adicionar os estilos que iremos utilizar em nosso exemplo abaixo

da classe App;

JavaScript import React, { Component } from 'react'; import { View, Text, StyleSheet } from 'react-native'; export default class App extends Component { ... } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center' }, bigBlue: { color: 'blue', fontSize: 50 }, smallRed: { color: 'red', fontSize: 20 } });

Tabela 3.3 – Definindo Estilos

3. Agora, dentro da classe App, vamos substituir o código do método render pelo disponível na Tabela 3.4 – Utilizando Estilos.

JavaScript import React, { Component } from 'react'; import { View, Text, StyleSheet } from 'react-native'; export default class App extends Component { render() { return (

Page 30: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

29

<View style={styles.container}> <Text style={styles.bigBlue}>Big Blue</Text> <Text style={styles.smallRed}>Small Red</Text> </View>); } }

Tabela 3.4 – Utilizando Estilos

Este é um exemplo bem simples. Apenas alteramos a cor e o tamanho da

fonte. O mais importante a observar nesse exemplo é a forma na qual referenciamos o

estilo, ou seja, se observarmos a propriedade style dos dois componentes Text notaremos que estamos referenciando aos estilos bigBlue e smallRed criados através

da constante styles.

Podemos observar o resultado do código disponível na Tabela 3.4 – Utilizando

Estilos nas figuras Figura 3.10 – Estilo aplicado no iPhone e Figura 3.11 – Estilo aplicado

no Android.

Figura 3.10 – Estilo aplicado no iPhone

Figura 3.11 – Estilo aplicado no Android

Nosso arquivo App.js completo está disponível na Tabela 3.5 – Arquivo App.js.

JavaScript import React, { Component } from 'react'; import { StyleSheet, Text, View } from 'react-native'; export default class App extends Component { render() {

Page 31: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

30

return ( <View style={styles.container}> <Text style={styles.bigBlue}>Big Blue</Text> <Text style={styles.smallRed}>Small Red</Text> </View> ); } } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center' }, bigBlue: { color: 'blue', fontSize: 50 }, smallRed: { color: 'red', fontSize: 20 } });

Tabela 3.5 – Arquivo App.js

3.3 LAYOUT E FLEXBOX

Antes de iniciarmos de fato o desenvolvimento do nosso projeto

ToDoManager, é extremamente importante entendemos como o posicionamento dos

componentes se comportam no React Native.

React Native fornece um recurso conhecido como Flexbox, ao qual foi

desenvolvido para prover layouts consistentes em tamanhos de telas diferentes. Com o

Flexbox definimos como será o posicionamento dos elementos filhos de um componente.

Podemos definir que os elementos filhos serão posicionados horizontalmente, um a baixo

do outro, que ocuparão todo o espaço disponível ou apenas metade desse espaço,

centralizados verticalmente, entre outras possibilidades.

Basicamente, utilizamos quatro propriedades: flex, flexDirection, alignItems

e justifyContent.

Propriedade Descrição flex A propriedade flex determina qual será o tamanho do componente de forma

dinâmica, de acordo com o tamanho disponível. Por exemplo, se em uma linha possuir três componentes com a propriedade flex igual a 1, 2 e 3, respectivamente, o primeiro componente ocupará 1/6 (16 %) da linha, o segundo 2/6 (33%) da linha e o último componente ocupará 3/6 (50%) da linha.

Page 32: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

31

Notamos que o número 6, o divisor dos cálculos, é a soma da propriedade flex dos três componentes da linha.

flexDirection A propriedade flexDirection determina como os componentes filhos serão organizados. flexDirection: ‘row’ indica que os componentes serão organizados em linhas, ou seja, horizontalmente. flexDirection: ‘column’ indica que os componentes serão organizados em colunas, isto é, verticalmente.

justifyContent A propriedade justifyContent determina como os componentes filhos serão alinhados. O alinhamento é em relação a direção definida na propriedade flexDirection, isto é, se a direção for definida horizontalmente – igual a row –, o alinhamento também será na horizontal. flexDirection: ‘row’, justifyContent: ‘center’ indica que os componentes serão centralizados horizontalmente. flexDirection: ‘column’, justifyContent: ‘center’ indica que os componentes serão centralizados verticalmente. Existem ainda outras opções como o flex-start, flex-end, space-around, space-between e space-evenly. justifyContent: ‘space-around’ indica que os componentes serão posicionados com espaços iguais nas extremidades. justifyContent: ‘space-between’ indica que os componentes serão posicionados com espaços iguais entre os elementos. justifyContent: ‘space-evenly’ indica que os componentes serão posicionados com espaços iguais nas extremidades e entre os elementos.

alignItems A propriedade alignItems também determina como os componentes filhos serão alinhados. No entanto o alinhamento é em relação oposta a direção definida na propriedade flexDirection, isto é, se a direção for definida horizontalmente – igual a row –, o alinhamento será na vertical. flexDirection: ‘row’, alignItems: ‘center’ indica que os componentes serão centralizados verticalmente, ou seja, no sentido oposto da direção. flexDirection: ‘column’, alignItems: ‘center’ indica que os componentes serão centralizados horizontalmente, ou seja, no sentido oposto da direção.

Tabela 3.6 – Propriedades Flexbox

Para entendermos melhor, vamos a um exemplo.

1. Com nosso arquivo App.js aberto, vamos alterar nosso método render de

acordo com o disponível na Tabela 3.7 – View com Flexbox.

JavaScript import React, { Component } from 'react'; import { StyleSheet, SafeAreaView, View } from 'react-native'; export default class App extends Component { render() { return ( <SafeAreaView ref='main' style={styles.container}>

Page 33: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

32

<View ref='first' style={styles.first}> <View style={styles.subView} /> <View style={styles.subView} /> <View style={styles.subView} /> </View> <View ref='second' style={styles.second}> <View style={styles.subView} /> <View style={styles.subView} /> <View style={styles.subView} /> </View> </SafeAreaView> ); } } const styles = StyleSheet.create({ container: { flex: 1, flexDirection: 'column' }, first: { flex: 1, flexDirection: 'row', justifyContent: 'space-between', alignItems: flex-start, margin: 40, borderColor: 'red', borderWidth: 1 }, second: { flex: 2, flexDirection: 'column', justifyContent: 'space-evenly', alignItems: flex-end, margin: 40, borderColor: 'red', borderWidth: 1 }, subView: { height: 50, width: 50, backgroundColor: 'skyblue' }, });

Tabela 3.7 – View com Flexbox

O primeiro componente View referenciado como main cujo a propriedade flex

é igual a 1 indica que o componente ocupará todo o espaço disponível. Como o

componente é a raiz da página, logo, o espaço utilizado será a página toda. A

propriedade flexDirection igual a column indica que os componentes filhos serão

posicionados um em baixo do outro. Esses componentes são as duas Views com bordas

vermelhas, referenciados como first e second.

Page 34: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

33

As Views first e second possuem os valores da propriedade flex iguais a 1

e 2, respectivamente. Isso quer dizer que a View main será dividida em três partes. A

primeira parte será ocupada pela View first. Já a View second ocupará os espaços

referentes as partes dois e três.

A View first com a propriedade flexDirection igual a row indica que os

componentes filhos serão posicionados um ao lado do outro, ou seja, serão posicionados

horizontalmente. A propriedade justifyContent igual a space-between indica que os

componentes serão posicionados com espaços iguais entre eles e a propriedade

alignItems igual a flex-end indica que os componentes filhos serão posicionados

verticalmente na parte inferior.

A View second com a propriedade flexDirection igual a column indica que

os componentes filhos serão posicionados um em abaixo do outro. A propriedade

justifyContent igual a space-evenly indica que os espaços das extremidades e os

espaços entre os componentes serão iguais, e a propriedade alignItems igual a flex-start indica que os componentes filhos serão alinhados horizontalmente a esquerda.

Veja o resultado do código disponível na Tabela 3.7 – View com Flexbox nas

imagens Figura 3.12 – iPhone com Flexbox e Figura 3.13 – Android com Flexbox.

Page 35: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

34

Figura 3.12 – iPhone com Flexbox

Figura 3.13 – Android com Flexbox

A primeira impressão parece um pouco confusa, mas vamos praticar esses

conceitos durante a construção do nosso projeto. Uma outra dica é jogar o Flexbox Froggy. É um jogo bem legal onde o objetivo é posicionar os sapos em um círculo.

Acessamos esse jogo através do link https://flexboxfroggy.com.

3.4 TELA DE LOGIN

Agora que temos um breve conceito de como o layout funciona em React Native, vamos começar a codificar o nosso projeto.

1. Com o nosso projeto aberto no VS Code, crie um arquivo Login.js dentro

da pasta src/screens/; 2. Com o arquivo Login.js aberto, vamos começar a codificar. Vamos criar a

classe Login e definir alguns estilos;

JavaScript import React, { Component } from 'react'; import { StyleSheet } from 'react-native'; const img = require('../assets/TodoList.png');

Page 36: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

35

export default class Login extends Component { ... } const styles = StyleSheet.create({ container: { flex: 1, flexDirection: 'column' }, topView: { justifyContent: 'center', alignItems: 'center', padding: 50 }, img: { width: 200, height: 200 }, bottomView: { flexDirection: 'column', paddingRight: 20, paddingLeft: 20 }, input: { marginBottom: 20 }, textConteiner: { flexDirection: 'row', justifyContent: 'center', marginTop: 20 }, textRegister: { fontWeight: 'bold' } });

Tabela 3.8 – Código fonte da classe Login

No trecho de código apresentado na Tabela 3.8 – Código fonte da classe

Login importamos o objeto StyleSheet porque iremos utilizar em nossa classe Login.

Também definimos uma referência para uma imagem e definimos os estilos que iremos

utilizar em nossa classe Login.

3. O próximo passo é definir o conteúdo de nossa classe Login. Vamos

localizar o método render e alterar de acordo com o código apresentado

na Tabela 3.9 – Definindo o conteúdo do Login;

JavaScript ... render() { return ( <SafeAreaView style={{ flex: 1 }}> <KeyboardAvoidingView style={styles.container} behavior='padding'> <View style={styles.topView}>

Page 37: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

36

<Image style={styles.img} source={img} /> </View> <View style={styles.bottomView}> <TextInput style={styles.input} placeholder='Email' keyboardType={'email-address'} autoCapitalize='none' /> <TextInput style={styles.input} placeholder='Password' secureTextEntry={true} /> <Button title='Sign In' /> <View style={styles.textConteiner}> <Text>Not a member? Let's </Text> <Text style={styles.textRegister}> Register </Text> </View> </View> </KeyboardAvoidingView> </SafeAreaView> ); } ...

Tabela 3.9 – Definindo o conteúdo do Login

O conteúdo de nosso componente Login possui a seguinte hierarquia:

• KeyboardAvoidingView principal que ocupa a tela inteira e seus

componentes filhos são posicionados um abaixo do outro:

o View que é posicionada na metade superior da tela:

§ Image que é posicionada ao centro, cujo o tamanho é

200x200;

o View que é posicionada na metade inferior da tela e seus

componentes filhos são posicionados um abaixo do outro:

§ TextInput para email; § TextInput para password; § Button para realizar a autenticação; § View com seus componentes filhos:

• Text para o texto “Not a member? Let’s”;

• Text para o texto “Register”.

Se observarmos o código da Tabela 3.9 – Definindo o conteúdo do Login não

mencionamos o componente SafeAreaView. O propósito desse componente é ajustar o

preenchimento das bordas que não são cobertas por barras de navegação, guias, etc.

Page 38: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

37

Em outras palavras, esse é um recurso que se aplica ao iPhone X cujo a borda superior

não é preenchida pela barra de navegação.

4. Na sequência, temos que importar os objetos que utilizamos;

JavaScript import React, { Component } from 'react'; import { SafeAreaView, KeyboardAvoidingView, View, Image, TextInput, Button, Text, StyleSheet } from 'react-native'; ...

Tabela 3.10 – Ajustando os imports do Login

5. O último passo é abrir o arquivo Index.js e atualizar o código de acordo

com o disponível na Tabela 3.11 – Código do arquivo index.js atualizado.

JavaScript import { AppRegistry } from 'react-native'; import Login from './src/screens/Login';

AppRegistry.registerComponent('ToDoManager', () => Login);

Tabela 3.11 – Código do arquivo index.js atualizado

Podemos observar o resultado do nosso código através das imagens Figura

3.14 – Tela de login no iPhone e Figura 3.15 – Tela de login no Android.

Page 39: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

38

Figura 3.14 – Tela de login no iPhone

Figura 3.15 – Tela de login no Android

O código completo de nossa classe Login está disponível na Tabela 3.12 –

Classe Login.

JavaScript import React, { Component } from 'react'; import { SafeAreaView, KeyboardAvoidingView, StyleSheet, View, Image, TextInput, Button, Text, SafeAreaView, Alert } from 'react-native'; const img = require('../assets/TodoList.png'); export default class Login extends Component { render() { return ( <SafeAreaView style={{ flex: 1 }}> <KeyboardAvoidingView style={styles.container} behavior='padding'> <View style={styles.topView}> <Image style={styles.img} source={img} /> </View> <View style={styles.bottomView}> <TextInput style={styles.input} placeholder='Email' keyboardType={'email-address'} autoCapitalize='none' /> <TextInput style={styles.input} placeholder='Password' secureTextEntry={true} /> <Button title='Sign In'/> <View style={styles.textConteiner}> <Text>Not a member? Let's </Text>

Page 40: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

39

<Text style={styles.textRegister}> Register </Text> </View> </View> </KeyboardAvoidingView> </SafeAreaView> ); } }

const styles = StyleSheet.create({ container: { flex: 1, flexDirection: 'column' }, topView: { justifyContent: 'center', alignItems: 'center', padding: 50 }, img: { width: 200, height: 200 }, bottomView: { flexDirection: 'column', paddingRight: 20, paddingLeft: 20 }, input: { marginBottom: 20 }, textConteiner: { flexDirection: 'row', justifyContent: 'center', marginTop: 20 }, textRegister: { fontWeight: 'bold' } });

Tabela 3.12 – Classe Login

O código completo da classe App Tabela 3.13 – Classe index com Login.

JavaScript import { AppRegistry } from 'react-native'; import Login from './src/screens/Login'; import { name as appName } from './app.json'; AppRegistry.registerComponent(appName, () => Login);

Tabela 3.13 – Classe index com Login

3.5 PROPS E STATE

Antes de implementarmos a autenticação de fato, precisamos entender dois

conceitos do React Native: Props e State.

Page 41: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

40

Existem dois tipos de estrutura de dados em um componente. Um desses

tipos é o Props, cujo se caracteriza por ser imutável e é utilizado para o componente pai

passar valores como parâmetros. Outro tipo de estrutura de dados é o State que, ao

contrário do Props, seus valores podem ser alterados, ou seja, é mutável.

Melhor entendermos o Props com um exemplo.

1. Vamos abrir o arquivo index.js e alterar o código de acordo com código

apresentado na Tabela 3.14 – Props como parâmetro.

JavaScript import React, { Component } from 'react'; import { AppRegistry } from 'react-native'; import Login from './src/screens/Login'; import { name as appName } from './app.json'; class Index extends Component { render() { return (<Login email='[email protected]' />); } } AppRegistry.registerComponent(appName, () => Index);

Tabela 3.14 – Props como parâmetro

Observe que no componente <Login/> estamos acrescentando uma

propriedade chamada email e atribuindo o valor ‘[email protected]’. Em outras

palavras, o componente pai, que neste caso é classe App que criamos, passa para o

componente <Login/> um parâmetro, cujo não será alterado durante todo o ciclo de vida

do componente <Login/>.

Para recuperarmos esse valor no componente <Login/> temos que codificar

um pouquinho.

2. Vamos abrir o arquivo Login.js, localizar o método render e adicionar a

propriedade value={this.props.email} no componente <TextInput/> do

email. Observe o código fonte disponível na Tabela 3.15 – Recuperando

Props como parâmetro.

JavaScript render() { return ( <SafeAreaView style={{ flex: 1 }}> <KeyboardAvoidingView style={styles.container} behavior='padding'> <View style={styles.topView}>

Page 42: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

41

<Image style={styles.img} source={img} /> </View> <View style={styles.bottomView}> <TextInput style={styles.input} value={this.props.email} placeholder='Email' keyboardType={'email-address'} autoCapitalize='none' /> ...

Tabela 3.15 – Recuperando Props como parâmetro

Como vimos no início do capítulo, o outro tipo de estrutura de dados é o State. No entanto, apenas vimos, não codificamos nada ainda. Então, vamos fazer algumas

alterações na classe Login.

3. A primeira alteração é a declaração dos nossos states. Vamos observar o

trecho de código da Tabela 3.16 – Declarando states na classe Login;

JavaScript ... export default class Login extends Component { state = { email: this.props.email, password: '' }; ...

Tabela 3.16 – Declarando states na classe Login

4. Na sequência, vamos localizar o método render e implementar o evento

onChangeText nos componentes <TextInput/>. Também vamos

aproveitar para implementar o evento onPress do componente <Button/>.

Assim, conseguiremos testar os nossos states. Observe o código

apresentado na Tabela 3.17 – Alterando os States na classe Login;

JavaScript ... <View style={styles.bottomView}> <TextInput style={styles.input} value={this.state.email} placeholder='Email' keyboardType={'email-address'} autoCapitalize='none' onChangeText={(text) => this.setState({ email: text })} /> <TextInput style={styles.input} placeholder='Password' secureTextEntry={true} onChangeText={(password) => this.setState({ password })} /> <Button title='Sign In' onPress={() => Alert.alert(`Email: ${this.state.email} \nPassword: ${this.state.password}`)} /> ...

Page 43: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

42

Tabela 3.17 – Alterando os States na classe Login

Fizemos três alterações no nosso código e a primeira foi utilizar o evento

onChangeText do componente <InputText/> para capturar o e-mail digitado pelo

usuário e atribuir no state email. A segunda alteração também foi utilizar o evento

onChangeText do componente <InputText/>, mas dessa vez para capturar a senha

digitada pelo usuário e atribuir no state password. A última alteração foi utilizar o evento

onPress do componente <Button/> para apresentar uma alerta com o e-mail e senha

digitados.

Podemos ver nosso código completo da classe Login na Tabela 3.18 –

Refactor do Login com States.

JavaScript import React, { Component } from 'react'; import { StyleSheet, SafeAreaView, KeyboardAvoidingView, View, Image, TextInput, Button, Text, Alert } from 'react-native'; const img = require('../assets/TodoList.png'); export default class Login extends Component { state = { email: this.props.email, password: '' }; render() { return ( <SafeAreaView style={{ flex: 1 }}> <KeyboardAvoidingView style={styles.container} behavior='padding'> <View style={styles.topView}> <Image style={styles.img} source={img} /> </View> <View style={styles.bottomView}> <TextInput style={styles.input} value={this.state.email} placeholder='Email' keyboardType={'email-address'} autoCapitalize='none' onChangeText={(text) => this.setState({ email: text })} /> <TextInput style={styles.input} placeholder='Password' secureTextEntry={true} onChangeText={(text) => this.setState({ password: text })} /> <Button title='Sign In' onPress={() => Alert.alert(`Email: ${this.state.email} \nPassword: ${this.state.password}`)} /> <View style={styles.textConteiner}> <Text>Not a member? Let's </Text>

Page 44: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

43

<Text style={styles.textRegister}> Register </Text> </View> </View> </KeyboardAvoidingView> </SafeAreaView> ); } } const styles = StyleSheet.create({ container: { flex: 1 }, topView: { justifyContent: 'center', alignItems: 'center', padding: 50 }, img: { width: 200, height: 200 }, bottomView: { flexDirection: 'column', paddingRight: 20, paddingLeft: 20 }, input: { marginBottom: 20 }, textConteiner: { flexDirection: 'row', justifyContent: 'center', marginTop: 20 }, textRegister: { fontWeight: 'bold' } });

Tabela 3.18 – Refactor do Login com States

Para testarmos nosso código vamos digitar um conteúdo qualquer nos inputs

do Email e Password e pressionar o botão Sign In. Se tudo funcionar como esperado,

uma alerta será apresentada com o conteúdo digitado.

3.6 TELA DE REGISTRO

Antes de estudarmos a navegação entre telas e integrarmos nosso projeto

com o Firebase vamos criar nossa página de registro de usuário.

Page 45: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

44

1. Com o nosso projeto aberto no VS Code, crie um arquivo Register.js

dentro da pasta src/screens/; 2. Com o arquivo Register.js aberto, vamos criar a classe Register e o

estilos que iremos utilizar. Vamos observar o código disponível na Tabela

3.19 – Código fonte da classe Register;

JavaScript import React, { Component } from 'react'; import { StyleSheet } from 'react-native'; const img = require('../assets/TodoList.png'); export default class Register extends Component { ... } const styles = StyleSheet.create({ container: { flex: 1, flexDirection: 'column', justifyContent: 'center' }, topView: { flex: 0.20, flexDirection: 'row', alignItems: 'center', padding: 25 }, img: { width: 50, height: 50 }, title: { fontSize: 20, fontWeight: 'bold', marginLeft: 20 }, bottomView: { flex: 1, flexDirection: 'column', paddingRight: 20, paddingLeft: 20 }, input: { marginBottom: 20 } });

Tabela 3.19 – Código fonte da classe Register

3. Temos que definir a estrutura dos states para receber os dados

preenchidos no e-mail e password;

JavaScript state = { email: '',

Page 46: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

45

password: '' }

Tabela 3.20 – Declarando os states da classe Register

4. Vamos implementar o conteúdo de nossa classe Register. Vamos

localizar o método render e trabalhar no visual;

JavaScript render() { return ( <SafeAreaView style={{ flex: 1 }}> <KeyboardAvoidingView style={styles.container} behavior='padding'> <View style={styles.topView}> <Image style={styles.img} source={img} /> <Text style={styles.title}>Registering new user</Text> </View> <View style={styles.bottomView}> <TextInput style={styles.input} placeholder='Email' keyboardType={'email-address'} autoCapitalize='none' onChangeText={email => this.setState({ email })} /> <TextInput style={styles.input} placeholder='Password' secureTextEntry={true} onChangeText={password => this.setState({ password })} /> <Button title='Register User' onPress={() => Alert.alert(`Email: ${this.state.email}\n Password: ${this.state.password}`)} /> </View> </KeyboardAvoidingView> </SafeAreaView> ); }

Tabela 3.21 – Definindo o método render da classe Register

Antes de seguirmos com a codificação de nossa classe Register, e como

forma de exercício para fixarmos o entendimento do flexbox, vamos entender como ficou

a hierarquia de nossa classe:

• KeyboardAvoidingView principal que ocupa a tela inteira e seus

componentes filhos são posicionados um abaixo do outro:

o View que é posicionada no ¼ superior da tela e seus elementos

filhos são posicionados um ao lado do outro:

§ Image que é posicionada ao esquerdo, cujo o tamanho é

50x50;

§ Text que é posicionado ao lado direito da Image.

Page 47: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

46

o View que é posicionada no ¾ inferior da tela e seus componentes

filhos são posicionados um abaixo do outro:

§ TextInput para email; § TextInput para password; § Button para realizar o registro.

Se observarmos o código da Tabela 3.21 – Definindo o método render da

classe Register novamente iremos encontrar o componente SafeAreaView, mas já

sabemos o motivo, ou seja, O propósito desse componente é ajustar o preenchimento

das bordas que não são cobertas por barras de navegação, guias, etc.

5. Para finalizarmos a codificação de nossa classe Register, vamos importar

os componentes que utilizamos;

JavaScript import React, { Component } from 'react'; import { SafeAreaView, KeyboardAvoidingView, View, Image, Text, TextInput, Button, StyleSheet, Alert } from 'react-native'; ...

Tabela 3.22 – Ajustando os imports da classe Register

6. E para testarmos nossa classe Register, vamos abrir o arquivo index.js e

atualizar o código de acordo com o disponível na Tabela 3.23 – Código da

classe index atualizado.

JavaScript import { AppRegistry } from 'react-native'; import Register from './src/screens/Register'; import { name as appName } from './app.json'; AppRegistry.registerComponent(appName, () => Register);

Tabela 3.23 – Código da classe index atualizado

Podemos observar o resultado do nosso código através das imagens Figura

3.16 – Tela de registro no iPhone e Figura 3.17 – Tela de registro no Android.

Page 48: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

47

Figura 3.16 – Tela de registro no iPhone

Figura 3.17 – Tela de registro no Android

Nossa classe Register completa ficou igual ao código apresentado na Tabela

3.24 – Classe Register.

JavaScript import React, { Component } from 'react'; import { SafeAreaView, KeyboardAvoidingView, View, Image, Text, TextInput, Button, StyleSheet, Alert } from 'react-native'; const img = require('../assets/TodoList.png'); export default class Register extends Component { state = { email: '', password: '' } render() { return ( <SafeAreaView style={{ flex: 1 }}> <KeyboardAvoidingView style={styles.container} behavior='padding'> <View style={styles.topView}> <Image style={styles.img} source={img} /> <Text style={styles.title}>Registering new user</Text> </View> <View style={styles.bottomView}> <TextInput style={styles.input} placeholder='Email' keyboardType={'email-address'}

Page 49: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

48

autoCapitalize='none' onChangeText={email => { this.setState({ email }) }} /> <TextInput style={styles.input} placeholder='Password' secureTextEntry={true} onChangeText={password => this.setState({ password })} /> <Button title='Register User' onPress={() => { Alert.alert(`Email: ${this.state.email}\n Password: ${this.state.password}`) }} /> </View> </KeyboardAvoidingView> </SafeAreaView> ); } } const styles = StyleSheet.create({ container: { flex: 1, flexDirection: 'column', justifyContent: 'center' }, topView: { flex: 0.20, flexDirection: 'row', alignItems: 'center', padding: 25 }, img: { width: 50, height: 50 }, title: { fontSize: 20, fontWeight: 'bold', marginLeft: 20 }, bottomView: { flex: 1, flexDirection: 'column', paddingRight: 20, paddingLeft: 20 }, input: { marginBottom: 20 } });

Tabela 3.24 – Classe Register

3.7 NAVEGAÇÃO ENTRE TELAS

Agora que temos duas telas precisamos realizar a navegação da tela de Login para a tela de Register. Para isso, vamos estudar uma biblioteca chamada React Navigation. Começaremos instalando a biblioteca.

Page 50: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

49

1. No terminal integrado do VS Code, vamos digitar o comando npm

install –-save react-navigation.

A instalação pode levar alguns minutos. Então, vamos aguardar a instalação

concluir para codificarmos um pouco.

2. Vamos aproveitar a oportunidade e criar o arquivo Screens.js dentro da

pasta src/screens. Vamos importar as classes Login e Register e, na

sequência, exportar suas referências;

JavaScript import Login from './Login'; import Register from './Register'; export { Login, Register };

Tabela 3.25 - Centralizando os exports das páginas

No trecho de código apresentado na Tabela 3.25 - Centralizando os exports

das páginas importamos as páginas Login e Register e criamos um esquema para

centralizar os imports e exports de nossas páginas. O objetivo é simplificar os imports

toda vez que precisarmos usar uma página. Veremos com ficará mais adiante.

3. Com o nosso projeto aberto no VS Code, crie um arquivo Routes.js dentro

da pasta src/services/; 4. Com o arquivo Routes.js aberto, vamos configurar nossas rotas de

navegação. Vamos observar o código disponível na Tabela 3.26 – Código

fonte das rotas de navegação;

JavaScript import { createStackNavigator } from 'react-navigation'; import { Login, Register } from '../screens/Screens'; export default Routes = createStackNavigator( { pageLogin: { screen: Login }, pageRegister: { screen: Register } }, { headerMode: 'screen' } );

Tabela 3.26 – Código fonte das rotas de navegação

Page 51: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

50

O código acima é bem simples. Importamos o método createStackNavigator e as páginas Login e Register. Observe que agora nossas páginas estão definidas

em ../screens/Screens e especificamos somente as páginas que iremos utilizar dentro

das chaves. Outro ponto importante a ser observado é o método createStackNavigator, responsável por configurar as rotas de navegação. Então, criamos uma constante

chamada Routes, que é uma instância do componente StackNavigator, e, por enquanto,

definimos duas rotas: Login e Register. Também definimos a propriedade headerMode como screen, ou seja, cada tela fica responsável em configurar a exibição da barra de

título.

5. Na sequência, vamos abrir o arquivo index.js e atualizar o código de

acordo com o disponível na Tabela 3.27 – Arquivo index.js atualizado com

rotas;

JavaScript import React from 'react'; import { AppRegistry, SafeAreaView } from 'react-native'; import Routes from './src/routes/Routes'; import { name as appName } from './app.json'; const wrappedRoutes = () => { return ( <SafeAreaView style={{ flex: 1 }}> <Routes /> </SafeAreaView> ); }; AppRegistry.registerComponent(appName, () => wrappedRoutes);

Tabela 3.27 – Arquivo index.js atualizado com rotas

Note que agora a responsabilidade em realizar a navegação fica por conta da

constante Routes. Outro ajuste que fizemos foi definir o objeto Routes como filho do

componente SafeAreaView. A partir de agora, qualquer página que navegarmos será

filha do objeto SafeAreaView. Com isso, evitaremos de definir o objeto SafeAreaView

como pai de todas as páginas que criarmos.

Neste ponto, se executarmos nosso aplicativo em Android ou iOS a tela de

Login deve ser apresentada. Falta pouco para concluirmos nossa navegação. Vamos

realizar alterações em mais duas classes.

Page 52: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

51

6. Vamos abrir a classe Login e acima do construtor vamos configurar a

propriedade navigationOptions;

JavaScript ... export default class Login extends Component { static navigationOptions = { header: null }; ...

Tabela 3.28 – Configuração da propriedade navigationOptions da classe Login

Neste caso, excluímos a cabeçalho de nossa classe Login, ou seja, excluímos

o título e barra de navegação de nossa classe Login.

7. Ainda em nossa classe Login, vamos alterar o componente

<Text>Register</Text> localizado no método render. Vamos codificar o

evento onPress e vamos aproveitar e remover o componente

<SafeAreView> do método render;

JavaScript ... render() { return ( <KeyboardAvoidingView style={styles.container} behavior='padding'> ... <Text style={styles.textRegister} onPress={() => { const { navigate } = this.props.navigation; navigate('pageRegister'); }} > Register </Text> ... </KeyboardAvoidingView> ); } ...

Tabela 3.29 – Navegando para a classe Register

No código da Tabela 3.29 – Navegando para a classe Register recuperamos

o objeto navigate das props utilizando um recurso do Javascript chamado destructing object, e navegamos para a página Register ao clicar sobre o texto Register. É

importante entender que nosso esquema de navegação definido no arquivo Routes.js passa como parâmetro o objeto navigation para todas as páginas. É por isso que

conseguimos recuperar o objeto navigation na página Login.

Page 53: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

52

Para finalizarmos a navegação, vamos realizar um ajuste na classe Register.

8. Vamos abrir a classe Register e acima do state, vamos configurar a

propriedade navigationOptions e remover o componente

<SafeAreView> do método render.

JavaScript ... export default class Register extends Component { static navigationOptions = { title: 'Register' }; ...

Tabela 3.30 – Configuração da propriedade navigationOptions da classe Register

Pronto! Se executarmos nossa aplicação, a classe Login será apresentada e

ao clicarmos no texto Register a aplicação navegará para a classe Register, mas desta

vez, com um detalhe a mais: título igual a Register e a seta de voltar para a tela Login.

Alteramos quatro classes para configurarmos a navegação inicial de nossa

aplicação e criamos um arquivo para nos ajudar nos imports das páginas. Vamos

observar o resultado dessas classes nas Tabela 3.31 - Esquema de imports e exports

das páginas, Tabela 3.32 – Código das rotas de navegação, Tabela 3.33 – Ajustando o

arquivo index.js, Tabela 3.34 – Código da classe Login navegando para a classe Register

e Tabela 3.35 – Código da classe Register com opções de navegação.

JavaScript import Login from './Login'; import Register from './Register'; export { Login, Register }

Tabela 3.31 - Esquema de imports e exports das páginas

JavaScript import { createStackNavigator } from 'react-navigation'; import { Login, Register } from '../screens/Screens'; export default Routes = createStackNavigator( { pageLogin: { screen: Login }, pageRegister: { screen: Register } }, { headerMode: 'screen' }

Page 54: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

53

); Tabela 3.32 – Código das rotas de navegação

JavaScript import React from 'react'; import { AppRegistry, SafeAreaView } from 'react-native'; import Routes from './src/routes/Routes'; import { name as appName } from './app.json'; const wrappedRoutes = () => { return ( <SafeAreaView style={{ flex: 1 }}> <Routes /> </SafeAreaView> ); }; AppRegistry.registerComponent(appName, () => wrappedRoutes);

Tabela 3.33 – Ajustando o arquivo index.js

JavaScript import React, { Component } from 'react'; import { StyleSheet, KeyboardAvoidingView, View, Image, TextInput, Button, Text, Alert } from 'react-native'; const img = require('../assets/TodoList.png'); export default class Login extends Component { static navigationOptions = { header: null }; state = { email: this.props.email, password: '' }; render() { return ( <KeyboardAvoidingView style={styles.container} behavior='padding'> <View style={styles.topView}> <Image style={styles.img} source={img} /> </View> <View style={styles.bottomView}> <TextInput style={styles.input} value={this.state.email} placeholder='Email' keyboardType={'email-address'} autoCapitalize='none' onChangeText={(text) => this.setState({ email: text })} /> <TextInput style={styles.input} placeholder='Password' secureTextEntry={true} onChangeText={(text) => this.setState({ password: text })} /> <Button title='Sign In' onPress={() => Alert.alert(`Email: ${this.state.email} \nPassword: ${this.state.password}`)} /> <View style={styles.textConteiner}> <Text>Not a member? Let's </Text>

Page 55: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

54

<Text style={styles.textRegister} onPress={() => { const { navigate } = this.props.navigation; navigate('pageRegister'); }}> Register </Text> </View> </View> </KeyboardAvoidingView> ); } } const styles = StyleSheet.create({ container: { flex: 1 }, topView: { justifyContent: 'center', alignItems: 'center', padding: 50 }, img: { width: 200, height: 200 }, bottomView: { flexDirection: 'column', paddingRight: 20, paddingLeft: 20 }, input: { marginBottom: 20 }, textConteiner: { flexDirection: 'row', justifyContent: 'center', marginTop: 20 }, textRegister: { fontWeight: 'bold' } });

Tabela 3.34 – Código da classe Login navegando para a classe Register

JavaScript import React, { Component } from 'react'; import { KeyboardAvoidingView, View, Image, Text, TextInput, Button, StyleSheet, Alert } from 'react-native'; const img = require('../assets/TodoList.png'); export default class Register extends Component { static navigationOptions = { title: 'Register' }; state = {

Page 56: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

55

email: '', password: '' } render() { return ( <KeyboardAvoidingView style={styles.container} behavior='padding'> <View style={styles.topView}> <Image style={styles.img} source={img} /> <Text style={styles.title}>Registering new user</Text> </View> <View style={styles.bottomView}> <TextInput style={styles.input} placeholder='Email' keyboardType={'email-address'} autoCapitalize='none' onChangeText={email => { this.setState({ email }) }} /> <TextInput style={styles.input} placeholder='Password' secureTextEntry={true} onChangeText={password => this.setState({ password })} /> <Button title='Register User' onPress={() => { Alert.alert(`Email: ${this.state.email}\n Password: ${this.state.password}`) }} /> </View> </KeyboardAvoidingView> ); } } const styles = StyleSheet.create({ container: { flex: 1, flexDirection: 'column', justifyContent: 'center' }, topView: { flex: 0.20, flexDirection: 'row', alignItems: 'center', padding: 25 }, img: { width: 50, height: 50 }, title: { fontSize: 20, fontWeight: 'bold', marginLeft: 20 }, bottomView: { flex: 1, flexDirection: 'column',

Page 57: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

56

paddingRight: 20, paddingLeft: 20 }, input: { marginBottom: 20 } });

Tabela 3.35 – Código da classe Register com opções de navegação

3.8 INTEGRAÇÃO COM O FIREBASE

Para realizarmos a autenticação do usuário precisamos integrar nossa

aplicação ao Firebase. Então, vamos instalar o Firebase utilizando o npm. A instalação

do Firebase é muito simples. Vamos aos passos.

1. No terminal integrado do VS Code vamos digitar o comando npm

install –-save firebase;

Pronto! Agora é só aguardar a instalação concluir para codificarmos um pouco.

Vamos criar alguns serviços para facilitar o uso da biblioteca do Firebase.

2. Com o nosso projeto aberto no VS Code, vamos criar o arquivo

FirebaseApi.js dentro da pasta src/services/; 3. Com o arquivo FirebaseApi.js aberto, vamos inserir o código disponível

na Tabela 3.36 – Código fonte do arquivo FirebaseApi;

JavaScript import firebase from 'firebase'; const config = { apiKey: "AIzaSyDtVC3VQ1Z8XzQYDkWwnTOC_NFo8ny5c90", authDomain: "todomanager-5444a.firebaseapp.com", databaseURL: "https://todomanager-5444a.firebaseio.com", projectId: "todomanager-5444a", storageBucket: "todomanager-5444a.appspot.com", messagingSenderId: "254572727152" }; export const initializeFirebaseApi = () => firebase.initializeApp(config);

Tabela 3.36 – Código fonte do arquivo FirebaseApi

Vamos entender essa integração com o Firebase. O primeiro passo é dizer

para o React Native que iremos utilizar a biblioteca do Firebase e fazemos isso

utilizando o import. No Firebase existe um o projeto “web” todomanager-5444a criado

Page 58: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

57

especificamente para utilizarmos no nosso projeto ToDoManager. Então, precisamos

carregar os dados desse projeto e utilizamos a constante config para armazenar tais

dados e para indicar a biblioteca do Firebase qual projeto carregar. Por último, criamos

um método initializeFirebaseApi para inicializar o serviço do Firebase e permitir acesso

aos serviços de autenticação e armazenagem.

3.9 REGISTRANDO USUÁRIO

Agora que temos nossas telas de Login e Register e a integração com o

Firebase, vamos consumir nosso primeiro serviço para registrar um usuário no Firebase.

1. Com o nosso projeto aberto no VS Code, vamos abrir o arquivo

FirebaseApi.js localizado dentro da pasta src/services/; 2. Com o arquivo FirebaseApi.js aberto, vamos inserir o código disponível

na Tabela 3.37 – Método para registrar usuário no Firebase abaixo do

método initializeFirebaseApi;

JavaScript ... export const createUserOnFirebaseAsync = async (email, password) => { const { user } = await firebase .auth() .createUserWithEmailAndPassword(email, password); return user; } ...

Tabela 3.37 – Método para registrar usuário no Firebase

O método createUserOnFirebaseAsync recebe como parâmetro o email e

password e repassa esses parâmetros invocando o método

createUserWithEmailAndPassword da biblioteca do Firebase. O método nos retorna

uma promessa de que o usuário será criado, mas caso ocorra algum erro, a promessa

repassa esse erro. Então, para saber se o usuário foi criado precisamos implementar

outro método.

3. Vamos precisar abrir outro arquivo. Este arquivo é o Register.js localizado

dentro da pasta src/screens/; 4. Com o arquivo Register.js aberto, vamos codificar um pouquinho.

Começaremos importando o componente Alert da biblioteca ‘react-native’

Page 59: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

58

e o método createUserOnFirebaseAsync que vamos utilizar da classe

FirebaseApi;

JavaScript ... import { KeyboardAvoidingView, View, Image, Text, TextInput, Button, Alert, StyleSheet } from 'react-native'; import { createUserOnFirebaseAsync } from '../services/FirebaseApi'; ...

Tabela 3.38 – Importando o método createUserOnFirebase da classe FirebaseApi

5. Ainda na classe Register, vamos codificar o método _createUserAsync

abaixo do método render;

JavaScript ... async _createUserAsync() { try { const user = await createUserOnFirebaseAsync(this.state.email, this.state.password); Alert.alert('User Created!', `User ${user.email} has succesfuly been created!`); } catch (error) { Alert.alert('Create User Failed!', error.message); } } ...

Tabela 3.39 – Método createUser da classe Register

O método _createUserAsync executa o método

createUserOnFirebaseAsync disponível na classe FirebaseApi. O método

createUserOnFirebaseAsync recebe como parâmetro o email e password e nos

retorna uma promessa de que o usuário será criado, mas caso ocorra algum erro, a

promessa repassa esse erro. Por enquanto, em ambos os casos, codificamos uma

mensagem de alerta para ser exibida, ou seja, em caso de sucesso a mensagem “User has succesfuly been created” será exibida, caso contrário, uma mensagem de erro

aparecerá.

6. Também precisamos alterar o evento onPress de nosso componente

<Button/>. Temos que executar o método _createUserAsync quando o

botão Register User for pressionado;

JavaScript ... render() { return ( <KeyboardAvoidingView style={styles.container}

Page 60: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

59

behavior='padding'> ... <Button title='Register User' onPress={() => this._createUserAsync()} /> ... </KeyboardAvoidingView> ); } ...

Tabela 3.40 – Evento onPress do botão Register User

Para testarmos o que codificação até o momento, vamos alterar mais uma

classe.

7. Vamos abrir o arquivo index.js localizado na raiz do projeto. Com o arquivo

index.js aberto, temos que importar o método initializeFirebaseApi e

executa-lo;

JavaScript ... import { initializeFirebaseApi } from './src/services/FirebaseApi'; AppRegistry.registerComponent(appName, () => { initializeFirebaseApi(); return wrappedRoutes; }); ...

Tabela 3.41 – Inicializando a biblioteca do Firebase

Neste ponto, ao entrar no aplicativo a biblioteca do Firebase é iniciada e a

tela de Login é apresentada. Para verificarmos se nossa codificação está correta, vamos

navegar para a tela de Register pressionando o texto Register localizado abaixo do

botão Sign In. Na tela de Register, vamos digitar o e-mail e senha e pressionar o botão

Register User. Se tudo estiver correto com os dados que digitamos as imagens Figura

3.18 – Registrando usuário no iPhone e Figura 3.19 – Registrando usuário no Android

serão apresentadas certificando de que o processo de registro de usuário funcionou

corretamente.

Agora, falta apenas um pequeno detalhe. Vamos codificar o botão de OK do

alerta de que o usuário foi criado com sucesso. Assim, quando o botão OK for

pressionado o alerta fechará e retornará para a tela de Login.

8. Vamos voltar para nossa classe Register e alterar o método

_createUserAsync de acordo com o trecho de código apresentado na

Tabela 3.42 – Voltando para o Login após usuário criado com sucesso;

Page 61: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

60

JavaScript ... async _createUserAsync() { try { const user = await createUserOnFirebaseAsync(this.state.email, this.state.password); Alert.alert("User Created", `User ${user.email} has succesfuly been created!`, [{ text: 'Ok', onPress: () => { this.props.navigation.goBack(); } }]); } catch (error) { Alert.alert('Create User Failed!', error.message); } } ...

Tabela 3.42 – Voltando para o Login após usuário criado com sucesso

Pronto! Agora podemos testar o registro de usuário.

Figura 3.18 – Registrando usuário no iPhone

Figura 3.19 – Registrando usuário no Android

Neste subcapítulo alteramos três classes. Vamos ver o resultado das classes

através das Tabela 3.43 - Classe FirebaseApi com o método

createUserOnFirebaseAsync, Tabela 3.44 – Inicialização na biblioteca do Firebase

através da classe index e Tabela 3.45 – Registrando usuário na classe Register.

JavaScript import firebase from 'firebase';

Page 62: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

61

const config = { apiKey: "AIzaSyDtVC3VQ1Z8XzQYDkWwnTOC_NFo8ny5c90", authDomain: "todomanager-5444a.firebaseapp.com", databaseURL: "https://todomanager-5444a.firebaseio.com", projectId: "todomanager-5444a", storageBucket: "todomanager-5444a.appspot.com", messagingSenderId: "254572727152" }; export const initializeFirebaseApi = () => firebase.initializeApp(config); export const createUserOnFirebaseAsync = async (email, password) => { const user = await firebase .auth() .createUserWithEmailAndPassword(email, password); return user; }

Tabela 3.43 - Classe FirebaseApi com o método createUserOnFirebaseAsync

JavaScript import React from 'react'; import { AppRegistry, SafeAreaView } from 'react-native'; import Routes from './src/routes/Routes'; import { name as appName } from './app.json'; import { initializeFirebaseApi } from './src/services/FirebaseApi'; const wrappedRoutes = () => { return ( <SafeAreaView style={{ flex: 1 }}> <Routes /> </SafeAreaView> ); }; AppRegistry.registerComponent(appName, () => { initializeFirebaseApi(); return wrappedRoutes; });

Tabela 3.44 – Inicialização na biblioteca do Firebase através da classe index

JavaScript import React, { Component } from 'react'; import { KeyboardAvoidingView, View, Image, Text, TextInput, Button, StyleSheet, Alert } from 'react-native'; import { createUserOnFirebaseAsync } from '../services/FirebaseApi'; const img = require('../assets/TodoList.png'); export default class Register extends Component { static navigationOptions = { title: 'Register' }; state = { email: '', password: '' } render() {

Page 63: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

62

return ( <KeyboardAvoidingView style={styles.container} behavior='padding'> <View style={styles.topView}> <Image style={styles.img} source={img} /> <Text style={styles.title}>Registering new user</Text> </View> <View style={styles.bottomView}> <TextInput style={styles.input} placeholder='Email' keyboardType={'email-address'} autoCapitalize='none' onChangeText={email => { this.setState({ email }) }} /> <TextInput style={styles.input} placeholder='Password' secureTextEntry={true} onChangeText={password => this.setState({ password })} /> <Button title='Register User' onPress={() => this._createUserAsync()} /> </View> </KeyboardAvoidingView> ); } async _createUserAsync() { try { const user = await createUserOnFirebaseAsync(this.state.email, this.state.password); Alert.alert("User Created", `User ${user.email} has succesfuly been created!`, [{ text: 'Ok', onPress: () => { this.props.navigation.goBack(); } }]); } catch (error) { Alert.alert('Create User Failed!', error.message); } } } const styles = StyleSheet.create({ container: { flex: 1, flexDirection: 'column', justifyContent: 'center' }, topView: { flex: 0.20, flexDirection: 'row', alignItems: 'center', padding: 25 }, img: { width: 50, height: 50 }, title: {

Page 64: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

63

fontSize: 20, fontWeight: 'bold', marginLeft: 20 }, bottomView: { flex: 1, flexDirection: 'column', paddingRight: 20, paddingLeft: 20 }, input: { marginBottom: 20 } });

Tabela 3.45 – Registrando usuário na classe Register

3.10 AUTENTICANDO USUÁRIO

No subcapítulo anterior codificamos o registro de um novo usuário. Neste

subcapítulo, vamos utilizar esse usuário registrado no processo de autenticação. Vamos

alterar duas classes: FirebaseApi.js e Login.js.

1. Com o nosso projeto aberto no VS Code, vamos abrir o arquivo

FirebaseApi.js localizado dentro da pasta src/services/; 2. Com o arquivo FirebaseApi.js aberto, vamos inserir o código disponível

na Tabela 3.46 – Método para autenticar usuário no Firebase abaixo do

método createUserOnFirebaseAsync;

JavaScript ... export async function signInOnFirebaseAsync(email, password) { const user = await firebase.auth().signInWithEmailAndPassword(email, password); return user; } ...

Tabela 3.46 – Método para autenticar usuário no Firebase

O método signInOnFirebaseAsync recebe como parâmetro o email e

password e repassa esses parâmetros invocando o método

signInWithEmailAndPassword da biblioteca do Firebase. O método nos retorna uma

promessa de que o usuário será autenticado, mas caso ocorra algum erro, a promessa

repassa esse erro. Então, para saber se o usuário foi autenticado com sucesso

precisamos implementar outro método.

3. Vamos abrir outro arquivo o Login.js localizado dentro da pasta

src/screens/;

Page 65: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

64

4. Com o arquivo Login.js aberto, vamos começar nossa codificação

importando o componente Alert da biblioteca ‘react-native’ e o método

signInOnFirebaseAsync da classe FirebaseApi;

JavaScript ... import React, { Component } from 'react'; import { SafeAreaView, KeyboardAvoidingView, StyleSheet, View, Image, TextInput, Button, Text, Alert } from 'react-native'; import { signInOnFirebaseAsync } from '../services/FirebaseApi'; ...

Tabela 3.47 – Importando o método signInOnFirebase da classe FirebaseApi

5. Ainda na classe Login, vamos criar o método _signInAsync abaixo do

método render;

JavaScript ... async signInAsync() { try { const user = await signInOnFirebaseAsync(this.state.email, this.state.password); Alert.alert("User Authenticated", `User ${user.email} has succesfuly been authenticated!`); } catch (error) { Alert.alert("Login Failed", error.message); } } ...

Tabela 3.48 [Método createUser da classe Register]

O método _signInAsync executa o método signInOnFirebaseAsync

disponível na classe FirebaseApi. O método signInOnFirebaseAsync recebe como

parâmetro o email e password e nos retorna uma promessa de que o usuário será

autenticado, mas caso ocorra algum erro, a promessa repassa esse erro. Por enquanto,

em ambos os casos, codificamos uma mensagem de alerta para ser exibida, ou seja, em

caso de sucesso a mensagem “User has succesfuly been authenticated” será exibida,

caso contrário, uma mensagem de erro aparecerá.

6. Também precisamos alterar o evento onPress de nosso componente

<Button/>. Temos que executar o método _signInAsync quando o botão

Sign In for pressionado;

JavaScript ... render() { return (

Page 66: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

65

<KeyboardAvoidingView style={styles.container} behavior='padding'> ... <Button title='Sign In' onPress={() => this._signInAsync()} /> ... </KeyboardAvoidingView> ); } ...

Tabela 3.49 – Evento onPress do botão Register User

Pronto! Já podemos testar nosso código. Na tela de Login, se preenchermos

os dados de e-mail e senha utilizados no registro do usuário e pressionarmos no botão

Sign In, teremos o nosso usuário autenticado com sucesso. Observe as figuras Figura

3.20 – Autenticando usuário no iPhone e Figura 3.21 – Autenticando usuário no Android.

Figura 3.20 – Autenticando usuário no iPhone

Figura 3.21 – Autenticando usuário no Android

Neste subcapítulo alteramos duas classes. Vamos ver o resultado das classes

através da Tabela 3.50 – Classe FirebaseApi com o método signInOnFirebase e Tabela

3.51 – Autenticando usuário na classe Login.

JavaScript import firebase from 'firebase'; const config = { apiKey: "AIzaSyDtVC3VQ1Z8XzQYDkWwnTOC_NFo8ny5c90", authDomain: "todomanager-5444a.firebaseapp.com", databaseURL: "https://todomanager-5444a.firebaseio.com", projectId: "todomanager-5444a",

Page 67: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

66

storageBucket: "todomanager-5444a.appspot.com", messagingSenderId: "254572727152" }; export const initializeFirebaseApi = () => firebase.initializeApp(config); export const createUserOnFirebaseAsync = async (email, password) => { const user = await firebase .auth() .createUserWithEmailAndPassword(email, password); return user; } export const signInOnFirebaseAsync = async (email, password) => { const user = await firebase .auth() .signInWithEmailAndPassword(email, password); return user; }

Tabela 3.50 – Classe FirebaseApi com o método signInOnFirebase

JavaScript import React, { Component } from 'react'; import { StyleSheet, KeyboardAvoidingView, View, Image, TextInput, Button, Text, Alert } from 'react-native'; import { signInOnFirebaseAsync } from '../services/FirebaseApi'; const img = require('../assets/TodoList.png'); export default class Login extends Component { static navigationOptions = { header: null }; state = { email: this.props.email, password: '' }; render() { return ( <KeyboardAvoidingView style={styles.container} behavior='padding'> <View style={styles.topView}> <Image style={styles.img} source={img} /> </View> <View style={styles.bottomView}> <TextInput style={styles.input} value={this.state.email} placeholder='Email' keyboardType={'email-address'} autoCapitalize='none' onChangeText={(text) => this.setState({ email: text })} /> <TextInput style={styles.input} placeholder='Password' secureTextEntry={true} onChangeText={(text) => this.setState({ password: text })} />

Page 68: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

67

<Button title='Sign In' onPress={() => this._signInAsync()} /> <View style={styles.textConteiner}> <Text>Not a member? Let's </Text> <Text style={styles.textRegister} onPress={() => { const { navigate } = this.props.navigation; navigate('pageRegister'); }}> Register </Text> </View> </View> </KeyboardAvoidingView> ); } async _signInAsync() { try { const user = await signInOnFirebaseAsync(this.state.email, this.state.password); Alert.alert("User Authenticated", `User ${user.email} has succesfuly been authenticated!`); } catch (error) { Alert.alert("Login Failed", error.message); } } } const styles = StyleSheet.create({ container: { flex: 1 }, topView: { justifyContent: 'center', alignItems: 'center', padding: 50 }, img: { width: 200, height: 200 }, bottomView: { flexDirection: 'column', paddingRight: 20, paddingLeft: 20 }, input: { marginBottom: 20 }, textConteiner: { flexDirection: 'row', justifyContent: 'center', marginTop: 20 }, textRegister: { fontWeight: 'bold' } });

Tabela 3.51 – Autenticando usuário na classe Login

Page 69: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

68

3.11 TELA DE LISTAGEM

Neste subcapítulo vamos iniciar a construção de nossa tela de listagem de

tarefas. Inicialmente, vamos construir somente a “casca” da tela de listagem.

1. Com o nosso projeto aberto no VS Code, vamos criar os arquivos

ToDoTasks.js e DoneTasks.js dentro da pasta src/screens/; 2. Com o arquivo ToDoTasks.js aberto, vamos criar a classe ToDoTasks;

JavaScript import React, { Component } from 'react'; import { Image, StyleSheet, View } from 'react-native';

const imgChecList = require('../assets/checklist.png');

export default class ToDoTasks extends Component { static navigationOptions = { tabBarLabel: 'To Do', tabBarIcon: ({ tintColor }) => ( <Image source={imgChecList} style={[styles.icon, { tintColor }]} /> ) } ... } const styles = StyleSheet.create({ container: { flex: 1, flexDirection: 'column', paddingLeft: 10, paddingRight: 10 }, icon: { width: 26, height: 26 }, img: { width: 50, height: 50 } });

Tabela 3.52 – Criando a classe ToDoTasks

Por enquanto, não codificamos muito em nossa classe ToDoTasks. Como

nossa tela ToDoTasks será uma aba da rota TasksList, definimos a imagem e o título

da aba. Essas configurações são específicas para o iOS. Também, definimos alguns

estilos que utilizaremos neste subcapítulo.

Page 70: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

69

3. Vamos codificar o método render. Por enquanto, o método render será

simples contendo apenas um botão flutuante caso a plataforma for

Android;

JavaScript ... render() { return ( <View style={styles.container} /> ); } ...

Tabela 3.53 – Criando floatButton na classe ToDoTasks

4. Agora, vamos criar o arquivo DoneTasks.js e praticamente replicar nossa

classe ToDoTasks para a classe DoneTasks. Com o arquivo

DoneTasks.js aberto, vamos criar a classe DoneTasks;

JavaScript import React, { Component } from 'react'; import { Image, StyleSheet, View } from 'react-native'; const imgDone = require('../assets/done.png'); export default class DoneTasks extends Component { static navigationOptions = { tabBarLabel: 'Done', tabBarIcon: ({ tintColor }) => (<Image source={imgDone} style={[styles.icon, { tintColor: tintColor }]} />) } ... } const styles = StyleSheet.create({ container: { flex: 1, flexDirection: 'column', paddingLeft: 10, paddingRight: 10 }, icon: { width: 26, height: 26 }, img: { width: 50, height: 50 } });

Tabela 3.54 – Criando a classe DoneTasks

Page 71: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

70

5. Vamos codificar o método render e adicionar um botão flutuante;

JavaScript ... render() { return ( <View style={ styles.conteiner }/> ); } ...

Tabela 3.55 – Criando floatButton na classe DoneTasks

Pronto! Nossas classes que serão as abas de nossa rota TasksList já estão

criadas. Vamos codificar a rota, mas antes, temos que importar nossas páginas no

arquivo de Screens.

6. Vamos abrir o arquivo Screens.js localizado na pasta src/screens e

importar as páginas ToDoTasks e DoneTasks;

JavaScript import Login from './Login'; import Register from './Register'; import ToDoTasks from './ToDoTasks'; import DoneTasks from './DoneTasks'; export { Login, Register, ToDoTasks, DoneTasks }

Tabela 3.56 - Importando as novas páginas no arquivo Screens

7. Também precisaremos abrir o arquivo Routes.js localizado na pasta

src/services e definir uma constante para nosso componente

TabNavigator com duas abas;

JavaScript import { createStackNavigator, createTabNavigator } from 'react-navigation'; import { Login, Register, ToDoTasks, DoneTasks } from '../screens/Screens'; const taskListTabNavigator = createTabNavigator({ pageToDoTasks: { screen: ToDoTasks, title: 'To Do' }, pageDoneTasks: { screen: DoneTasks, title: 'Done' } }); ...

Tabela 3.57 – Definindo a TabNavigator

O componente TabNavigator será composto por duas abas: aba com o título

‘To Do’ representada pela classe ToDoTasks; aba com o título ‘Done’ representada

pela classe DoneTasks.

Page 72: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

71

8. Agora podemos definir a rota TasksList;

JavaScript ... export default Routes = createStackNavigator( { pageLogin: { screen: Login }, pageRegister: { screen: Register }, pageTasksList: { screen: taskListTabNavigator, navigationOptions: { ...Platform.select({ ios: { title: 'Task List' }, android: { header: null } }) } } }, { headerMode: 'screen' } );

Tabela 3.58 – Rota para TasksList

A definição de uma rota composta por duas telas se da através da função

createTabNavigator. Essa função configura uma navegação em abas. Além disso,

utilizamos um recurso novo, isto é, utilizamos o objeto Platform para configurar

características diferentes para Android ou iOS. Neste caso, no iOS existirá o título

‘Tasks List’ na página TasksList e no Android removemos a barra de título.

Para testarmos, temos que alterar o método _signInAsync da classe Login.

Após realizar a autenticação vamos limpar o histórico de navegação e navegar para

TaskList.

9. Vamos abrir o arquivo Login.js localizado na pasta src/screens e alterar

o código do método _signInAsync de acordo com o trecho de código da

Tabela 3.59 - Método _signInAsync alterado;

JavaScript import { StackActions, NavigationActions } from 'react-navigation'; ... async signInAsync() { try { const user = await signInOnFirebaseAsync(this.state.email, this.state.password);

Page 73: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

72

const resetNavigation = StackActions.reset({ index: 0, actions: [NavigationActions.navigate({ routeName: 'pageTasksList' })] }); this.props.navigation.dispatch(resetNavigation); } catch (error) { Alert.alert("Login Failed", error.message); } } ...

Tabela 3.59 - Método _signInAsync alterado

Importamos os componentes StackActions e NavigationActions e

implementamos a navegação para a tela TasksList. Agora, quando realizarmos a

autenticação de nosso usuário limpamos o histórico de navegação e navegamos para a

página TasksList. Neste cenário, se não limparmos o histórico de navegação a tela

TasksList com as abas ToDo e Done será apresentada com a opção voltar no canto

superior esquerdo. Remover essa opção faz todo sentido pois com o usuário autenticado

nossa página inicial passa a ser a TasksList.

Observe o resultado de nossa codificação através das Figura 3.22 – Tela de

Listagem das Tarefas no iPhone e Figura 3.23 – Tela de Listagem das Tarefas no Android.

Figura 3.22 – Tela de Listagem das Tarefas no iPhone

Figura 3.23 – Tela de Listagem das Tarefas no Android

Neste subcapítulo alteramos cinco arquivos. Vamos ver os resultados dessas

alterações através da Tabela 3.60 – Aba ToDo representada pela classe ToDoTasks,

Page 74: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

73

Tabela 3.61 – Aba Done representada pela classe DoneTasks, Tabela 3.62 – Arquivo

Screens ajustado, Tabela 3.63 – TasksList com as abas ToDo e Done e Tabela 3.64 -

Classe Login com autenticação e navegação.

JavaScript import React, { Component } from 'react'; import { Image, StyleSheet, View } from 'react-native'; const imgChecList = require('../assets/checklist.png'); export default class ToDoTasks extends Component { static navigationOptions = { tabBarLabel: 'To Do', tabBarIcon: ({ tintColor }) => ( <Image source={imgChecList} style={[styles.icon, { tintColor }]} /> ) } render() { return ( <View style={styles.container} /> ); } } const styles = StyleSheet.create({ container: { flex: 1, paddingLeft: 10, paddingRight: 10 }, icon: { width: 26, height: 26 }, img: { width: 50, height: 50 } });

Tabela 3.60 – Aba ToDo representada pela classe ToDoTasks

JavaScript import React, { Component } from 'react'; import { Image, StyleSheet, View } from 'react-native'; const imgDone = require('../assets/done.png'); export default class DoneTasks extends Component { static navigationOptions = { tabBarLabel: 'Done', tabBarIcon: ({ tintColor }) => ( <Image source={imgDone} style={[styles.icon, { tintColor }]} /> )

Page 75: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

74

} render() { return ( <View style={styles.container} /> ); } } const styles = StyleSheet.create({ container: { flex: 1, paddingLeft: 10, paddingRight: 10 }, icon: { width: 26, height: 26 }, img: { width: 50, height: 50 } });

Tabela 3.61 – Aba Done representada pela classe DoneTasks

JavaScript import Login from './Login'; import Register from './Register'; import ToDoTasks from './ToDoTasks'; import DoneTasks from './DoneTasks'; export { Login, Register, ToDoTasks, DoneTasks }

Tabela 3.62 – Arquivo Screens ajustado

JavaScript import { createStackNavigator, createTabNavigator } from 'react-navigation'; import { Login, Register, ToDoTasks, DoneTasks } from '../screens/Screens'; import { Platform } from 'react-native'; const taskListTabNavigator = createTabNavigator({ pageToDoTasks: { screen: ToDoTasks, title: 'To Do' }, pageDoneTasks: { screen: DoneTasks, title: 'Done' } }); export default Routes = createStackNavigator( { pageLogin: { screen: Login }, pageRegister: { screen: Register }, pageTasksList: { screen: taskListTabNavigator, navigationOptions: { ...Platform.select({ ios: { title: 'Task List' },

Page 76: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

75

android: { header: null } }) } } }, { headerMode: 'screen' } );

Tabela 3.63 – TasksList com as abas ToDo e Done

JavaScript import React, { Component } from 'react'; import { StyleSheet, KeyboardAvoidingView, View, Image, TextInput, Button, Text, Alert } from 'react-native'; import { signInOnFirebaseAsync } from '../services/FirebaseApi'; import { StackActions, NavigationActions } from 'react-navigation'; const img = require('../assets/TodoList.png'); export default class Login extends Component { static navigationOptions = { header: null }; state = { email: this.props.email, password: '' }; render() { return ( <KeyboardAvoidingView style={styles.container} behavior='padding'> <View style={styles.topView}> <Image style={styles.img} source={img} /> </View> <View style={styles.bottomView}> <TextInput style={styles.input} value={this.state.email} placeholder='Email' keyboardType={'email-address'} autoCapitalize='none' onChangeText={(text) => this.setState({ email: text })} /> <TextInput style={styles.input} placeholder='Password' secureTextEntry={true} onChangeText={(text) => this.setState({ password: text })} /> <Button title='Sign In' onPress={() => this._signInAsync()} /> <View style={styles.textConteiner}> <Text>Not a member? Let's </Text> <Text style={styles.textRegister} onPress={() => { const { navigate } = this.props.navigation; navigate('pageRegister'); }}>

Page 77: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

76

Register </Text> </View> </View> </KeyboardAvoidingView> ); } async _signInAsync() { try { const user = await signInOnFirebaseAsync(this.state.email, this.state.password); const resetNavigation = StackActions.reset({ index: 0, actions: [NavigationActions.navigate({ routeName: 'pageTasksList' })] }); this.props.navigation.dispatch(resetNavigation); } catch (error) { Alert.alert("Login Failed", error.message); } } } const styles = StyleSheet.create({ container: { flex: 1 }, topView: { justifyContent: 'center', alignItems: 'center', padding: 50 }, img: { width: 200, height: 200 }, bottomView: { flexDirection: 'column', paddingRight: 20, paddingLeft: 20 }, input: { marginBottom: 20 }, textConteiner: { flexDirection: 'row', justifyContent: 'center', marginTop: 20 }, textRegister: { fontWeight: 'bold' } });

Tabela 3.64 - Classe Login com autenticação e navegação

Page 78: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

77

3.12 VERIFICANDO O ESTADO DO USUÁRIO

Nossa aplicação já está tomando corpo. Agora, ao inicializar nossa aplicação

iremos verificar se o usuário já se encontra autenticado. Caso não esteja autenticado,

vamos navegar à tela de Login. Caso contrário, iremos navegar à tela TasksList.

1. Com o nosso projeto aberto no VS Code, vamos abrir o arquivo

FirebaseApi.js localizado dentro da pasta src/services/; 2. Com o arquivo FirebaseApi.js aberto, vamos criar a função

currentFirebaseUser para verificar o estado do usuário;

JavaScript export const currentFirebaseUser = () => { return new Promise((resolve, reject) => { var unsubscribe = null; unsubscribe = firebase .auth() .onAuthStateChanged((user) => { resolve(user); }, (error) => { reject(error); }, () => { unsubscribe(); }); }); }

Tabela 3.65 – Método para autenticar usuário no Firebase

O método currentFirebaseUser nos retorna uma promessa indicando qual

usuário está autenticado, mas caso ocorra algum erro, significa que não existe usuário

algum autenticado. Essa verificação é realizada através do método

onAuthStateChanged da API do Firebase que implementa o padrão Publisher-Subscriber, ou seja, o método onAuthStateChanged avisa aos seus assinantes sobre

qualquer alteração do usuário e para receber esse aviso precisamos assiná-lo. Então,

nós assinamos esse método e quando o mesmo concluí sua execução, cancelamos essa

assinatura.

A assinatura do método onAuthStateChanged ocorre quando passamos

como parâmetro um observer representado pela arrow function (user) => { ... }. O

método onAuthStateChanged retorna uma referência dessa assinatura. No nosso caso,

guardamos a referência dessa assinatura na variável unsubscribe e vamos utilizá-la

para cancela essa assinatura assim que o método onAuthStateChanged retornar algo.

Page 79: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

78

Agora que estudamos como funciona o método onAuthStateChanged precisamos ajustar a inicialização de nossa aplicação.

3. Vamos criar o arquivo App.js dentro da pasta src/screens e implementar

a classe App de acordo com o trecho de código da Tabela 3.66 –

Implementando a classe App;

JavaScript import React, { Component } from 'react'; import { View, ActivityIndicator, StyleSheet } from 'react-native'; export default class App extends Component { static navigationOptions = { header: null }; render() { return ( <View style={styles.container}> <ActivityIndicator style={styles.loading} /> </View> ); } } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center' }, loading: { width: 50, height: 50 } });

Tabela 3.66 – Implementando a classe App

4. Agora, vamos ajustar os imports e adicionar o método

componentDidMount de acordo com o código apresentado na Tabela

3.67 – Verificando o estado do usuário;

JavaScript ... import { StackActions, NavigationActions } from 'react-navigation'; import { currentFirebaseUser } from '../services/FirebaseApi'; export default class App extends Component { ... async componentDidMount() { let resetNavigation = StackActions.reset({ index: 0,

Page 80: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

79

actions: [NavigationActions.navigate({ routeName: 'pageLogin' })] }); try { const user = await currentFirebaseUser(); if (user) { resetNavigation = StackActions.reset({ index: 0, actions: [NavigationActions.navigate({ routeName: 'pageTasksList' })] }); this.props.navigation.dispatch(resetNavigation); } this.props.navigation.dispatch(resetNavigation); } catch (error) { this.props.navigation.dispatch(resetNavigation); } } }

Tabela 3.67 – Verificando o estado do usuário

No código apresentado acima ajustamos os imports e adicionamos o método

componentDidMount para executar a função currentFirebaseUser disponível na

classe FirebaseApi.js. Essa função nos retorna o usuário atual. Se não houver usuário

algum autenticado, a aplicação navega para a tela de Login, caso contrário, navega à

tela TasksList.

Falta pouco para testarmos nossa aplicação. Precisamos ajustar o imports do

arquivo Screens.js e adicionar a página App em nossas rotas.

5. Vamos abrir o arquivo Screens.js localizado na pasta src/screens e

importar a classe App e, em seguida, exportá-la;

JavaScript import App from './App'; ... export { App, Login, Register, ToDoTasks, DoneTasks }

Tabela 3.68 - Importando a tela App no arquivo Screens

6. Agora, vamos abrir o arquivo Routes.js localizado na pasta src/routes;

7. Com o arquivo aberto, vamos importar a classe App e adicioná-la em

nossas rotas. Observe o trecho de código Tabela 3.69 – Ajustando as rotas.

JavaScript

Page 81: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

80

... import { App, Login, Register, ToDoTasks, DoneTasks } from '../screens/Screens'; ... export default Routes = createStackNavigator( { pageApp: { screen: App }, pageLogin: { screen: Login }, pageRegister: { screen: Register }, pageTasksList: { screen: taskListTabNavigator, navigationOptions: { ...Platform.select({ ios: { title: 'Task List' }, android: { header: null } }) } } }, { headerMode: 'screen' } );

Tabela 3.69 – Ajustando as rotas

Pronto! Agora vamos testar nossa aplicação. Agora, ao inicializar a aplicação

visualizaremos a tela App com uma ampulheta ao centro. Se existir algum usuário

autenticado a aplicação apresentará a tela de TasksList, caso contrário, veremos a tela

de Login.

Neste subcapítulo alteramos quatro classes. Vamos ver o resultado das

classes através da Tabela 3.70 – Método currentFirebaseUser que retorna o estado do

usuário, Tabela 3.71 – Navegação de acordo com o estado do usuário, Tabela 3.72 -

Screens.js ajustado e Tabela 3.73 – Adicionando página App nas rotas.

JavaScript import firebase from 'firebase'; const config = { apiKey: "AIzaSyDtVC3VQ1Z8XzQYDkWwnTOC_NFo8ny5c90", authDomain: "todomanager-5444a.firebaseapp.com", databaseURL: "https://todomanager-5444a.firebaseio.com", projectId: "todomanager-5444a", storageBucket: "todomanager-5444a.appspot.com", messagingSenderId: "254572727152" }; export const initializeFirebaseApi = () => firebase.initializeApp(config);

Page 82: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

81

export const createUserOnFirebaseAsync = async (email, password) => { const user = await firebase .auth() .createUserWithEmailAndPassword(email, password); return user; } export const signInOnFirebaseAsync = async (email, password) => { const user = await firebase .auth() .signInWithEmailAndPassword(email, password); return user; } export const currentFirebaseUser = () => { return new Promise((resolve, reject) => { var unsubscribe = null; unsubscribe = firebase .auth() .onAuthStateChanged((user) => { resolve(user); }, (error) => { reject(error); }, () => { unsubscribe(); }); }); }

Tabela 3.70 – Método currentFirebaseUser que retorna o estado do usuário

JavaScript import React, { Component } from 'react'; import { View, ActivityIndicator, StyleSheet } from 'react-native'; import { StackActions, NavigationActions } from 'react-navigation'; import { currentFirebaseUser } from '../services/FirebaseApi'; export default class App extends Component { static navigationOptions = { header: null }; render() { return ( <View style={styles.container}> <ActivityIndicator style={styles.loading} /> </View> ); } async componentDidMount() { let resetNavigation = StackActions.reset({ index: 0, actions: [NavigationActions.navigate({ routeName: 'pageLogin' })] }); try { const user = await currentFirebaseUser(); if (user) {

Page 83: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

82

resetNavigation = StackActions.reset({ index: 0, actions: [NavigationActions.navigate({ routeName: 'pageTasksList' })] }); this.props.navigation.dispatch(resetNavigation); } this.props.navigation.dispatch(resetNavigation); } catch (error) { this.props.navigation.dispatch(resetNavigation); } } } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center' }, loading: { width: 50, height: 50 } });

Tabela 3.71 – Navegação de acordo com o estado do usuário

JavaScript import App from './App'; import Login from './Login'; import Register from './Register'; import ToDoTasks from './ToDoTasks'; import DoneTasks from './DoneTasks'; export { App, Login, Register, ToDoTasks, DoneTasks }

Tabela 3.72 - Screens.js ajustado

JavaScript import { createStackNavigator, createTabNavigator } from 'react-navigation'; import { App, Login, Register, ToDoTasks, DoneTasks } from '../screens/Screens'; import { Platform } from 'react-native'; const taskListTabNavigator = createTabNavigator({ pageToDoTasks: { screen: ToDoTasks, title: 'To Do' }, pageDoneTasks: { screen: DoneTasks, title: 'Done' } }); export default Routes = createStackNavigator( { pageApp: { screen: App }, pageLogin: { screen: Login }, pageRegister: { screen: Register }, pageTasksList: { screen: taskListTabNavigator, navigationOptions: {

Page 84: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

83

...Platform.select({ ios: { title: 'Task List' }, android: { header: null } }) } } }, { headerMode: 'screen' } );

Tabela 3.73 – Adicionando página App nas rotas

3.13 TELA DE TAREFA

Neste subcapítulo, vamos construir a tela para incluir uma nova tarefa no

Firebase. Também iremos utilizar essa mesma tela para salvar alterações de uma tarefa.

No entanto, salvar essas alterações será assunto de um subcapítulo específico. Neste

subcapítulo vamos focar somente na inclusão.

1. Com o nosso projeto aberto no VS Code, vamos abrir o arquivo

FirebaseApi.js localizado dentro da pasta src/services/; 2. Com o arquivo FirebaseApi.js aberto, vamos criar o método

writeTaskOnFirebase;

JavaScript export const writeTaskOnFirebaseAsync = async (task) => { const user = await currentFirebaseUser(); var tasksReference = firebase .database() .ref(user.uid); const key = tasksReference .child('tasks') .push() .key; return await tasksReference .child(`tasks/${key}`) .update(task); }

Tabela 3.74 – Método para criar Task no Firebase

O método writeTaskOnFirebase recebe o parâmetro task – que é

representado por um json – e repassa esse parâmetro invocando o método update da

biblioteca do Firebase. O método nos retorna uma promessa de que a Task será criada,

Page 85: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

84

mas caso ocorra algum erro a promessa repassa esse erro. As Tasks são salvas

somente para o usuário corrente, ou seja, cada usuário visualiza somente suas Tasks.

Esse controle é realizado através do método

tasksReference.database().ref(user.uid) que recebe como parâmetro o usuário atual

autenticado.

3. Dando continuidade em nossa codificação, vamos criar o arquivo Task.js

dentro da pasta src/screens/; 4. Com o arquivo Task.js aberto, vamos cria a classe Task e definir alguns

estilos;

JavaScript import React, { Component } from 'react'; import { View, TextInput, Switch, Text, Button, StyleSheet } from 'react-native'; export default class Task extends Component { static navigationOptions = { title: 'Task' } ... } const styles = StyleSheet.create({ container: { flex: 1, flexDirection: 'column', padding: 20, }, input: { marginBottom: 20 }, multilineInput: { height: 100 }, switchContainer: { flexDirection: 'row', alignItems: 'center', paddingBottom: 20 }, switchText: { marginLeft: 10, color: 'black', fontSize: 18 }

Page 86: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

85

}); Tabela 3.75 – Definindo a classe Task

5. Vamos definir os states;

JavaScript ... state = { title: '', resume: '', priority: true, isDone: false }; ...

Tabela 3.76 - Definindo os states da classe Task

6. Vamos definir o método _saveTaskAsync e importar o método

writeTaskOnFirebase;

JavaScript ... import { writeTaskOnFirebaseAsync } from '../services/FirebaseApi'; ... async _saveTaskAsync() { var task = { title: this.state.title, resume: this.state.resume, priority: this.state.priority, isDone: this.state.isDone }; try { await writeTaskOnFirebaseAsync(task); this.props.navigation.goBack(); } catch (error) { Alert.alert("Erro Saving", error.message); } } ...

Tabela 3.77 [Método saveTask da classe Task]

O método _saveTaskAsync executa o método writeTaskOnFirebaseAsync

disponível na classe FirebaseApi. O método writeTaskOnFirebaseAsync recebe como

parâmetro um objeto que representa uma Task e nos retorna uma promessa de que a

Task será criada, mas caso ocorra algum erro a promessa repassa esse erro.

7. Por enquanto, o último trabalho em nossa classe Task é codificar o método

render;

JavaScript ... render() {

Page 87: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

86

return ( <View style={styles.container}> <TextInput style={styles.input} placeholder='Title' value={this.state.title} onChangeText={(value) => this.setState({ title: value })} /> <TextInput style={[styles.input, styles.multilineInput]} placeholder='Resume' multiline={true} numberOfLines={4} value={this.state.resume} onChangeText={(value) => this.setState({ resume: value })} /> <View style={styles.switchContainer}> <Switch value={this.state.priority} onValueChange={(value) => this.setState({ priority: value })} value={this.state.priority} /> <Text style={styles.switchText}>Hight Priority</Text> </View> <View style={styles.switchContainer}> <Switch value={this.state.isDone} onValueChange={(value) => this.setState({ isDone: value })} value={this.state.isDone} /> <Text style={styles.switchText}>Is Done?</Text> </View> <Button style={styles.button} title='Save' onPress={() => this._saveTaskAsync()} /> </View> ); } ...

Tabela 3.78 – Método render da classe Task

Antes de seguirmos com a codificação de nossa classe Task, e como forma

de exercício para fixarmos o entendimento do flexbox, vamos entender como ficou a

hierarquia de nossa classe:

• View principal que ocupa a tela inteira e seus componentes filhos são

posicionados um abaixo do outro:

o TextInput que posicionado no topo da tela;

o TextInput que posicionado abaixo do primeiro TextInput; o View que é posicionada abaixo do segundo TextInput, contendo

dois componentes que serão posicionados horizontalmente:

§ Switch que é alinhado ao lado esquerdo;

§ Text posicionado ao lado direito do componente Switch.

o View que é posicionada abaixo da primeira View filha, contendo

dois componentes que serão posicionados horizontalmente:

§ Switch que é alinhado ao lado esquerdo;

§ Text posicionado ao lado direito do componente Switch.

Page 88: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

87

o Button que é posicionado como último elemento, abaixo da última

View filha.

8. Vamos abrir nosso arquivo Screens.js localizado na pasta src/screens e

incluir a página Task em nosso esquema de import e export;

JavaScript ... import Task from './Task'; export { App, Login, Register, ToDoTasks, DoneTasks, Task }

Tabela 3.79 – Ajustando o esquema de import e export das páginas

9. Agora, temos que adicionar uma rota para nossa tela Task. Vamos abrir o

arquivo Routes.js localizado na pasta src/services e codificar essa nova

rota para nossa tela Task;

JavaScript ... import { App, Login, Register, ToDoTasks, DoneTasks, Task } from '../screens/Screens'; ... export default Routes = createStackNavigator( { pageApp: { screen: App }, pageLogin: { screen: Login }, pageRegister: { screen: Register }, pageTasksList: { screen: taskListTabNavigator, navigationOptions: { ...Platform.select({ ios: { title: 'Task List' }, android: { header: null } }) } }, pageTask: { screen: Task } }, { headerMode: 'screen' } );

Tabela 3.80 – Adicionando uma nova rota

Page 89: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

88

10. Precisamos navegar para a tela Task. Vamos abrir o arquivo

ToDoTasks.js, implementar o método _goToTask;

JavaScript ... _goToTask() { this.props.navigation.navigate('pageTask'); } ...

Tabela 3.81 [Método createTask que navega para Task]

11. Por último, vamos adicionar um botão no rodapé dá página ToDoTasks

que quando clicarmos vamos navegar para a página de Task. Observe

que temos que importar o componente TouchableOpacity, definir uma

imagem e adicionar um novo estilo.

JavaScript ... import { Image, StyleSheet, View, TouchableOpacity } from 'react-native'; const imgCheckList = require('../assets/checklist.png'); const imgPlus = require('../assets/plus_64.png'); export default class ToDoTasks extends Component { ... render() { return ( <View style={styles.container}> <TouchableOpacity style={styles.floatButton} onPress={() => this._goToTask()}> <Image source={imgPlus} style={styles.img} /> </TouchableOpacity> </View> ); } ... } const styles = StyleSheet.create({ container: { flex: 1, paddingLeft: 10, paddingRight: 10 }, icon: { width: 26, height: 26 }, img: { width: 50, height: 50 },

Page 90: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

89

floatButton: { position: 'absolute', right: 20, bottom: 20 } });

Tabela 3.82 – Evento onPress do float button

Podemos observar o resultado do nosso código através das imagens Error! Reference source not found. e Error! Reference source not found..

Figura 3.24 – Tela de Task no iPhone

Figura 3.25 – Tela de Task no Android

Neste subcapítulo alteramos quatro arquivos e criamos uma nova página.

Vamos ver o resultado desse trabalho através dos trechos de códigos apresentados na

Tabela 3.83 – Método writeTaskOnFirebaseAsync para criar Tasks, Tabela 3.84 – Classe

Task, Tabela 3.84 – Classe Task, Tabela 3.85 - Arquivo Screens com a página Task,

Tabela 3.86 – Definição da rota para Task e Tabela 3.87 – Navegando para tela Task.

JavaScript import firebase from 'firebase'; const config = { apiKey: "AIzaSyDtVC3VQ1Z8XzQYDkWwnTOC_NFo8ny5c90", authDomain: "todomanager-5444a.firebaseapp.com", databaseURL: "https://todomanager-5444a.firebaseio.com", projectId: "todomanager-5444a", storageBucket: "todomanager-5444a.appspot.com", messagingSenderId: "254572727152" };

Page 91: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

90

export const initializeFirebaseApi = () => firebase.initializeApp(config); export const createUserOnFirebaseAsync = async (email, password) => { const user = await firebase .auth() .createUserWithEmailAndPassword(email, password); return user; } export const signInOnFirebaseAsync = async (email, password) => { const user = await firebase .auth() .signInWithEmailAndPassword(email, password); return user; } export const currentFirebaseUser = () => { return new Promise((resolve, reject) => { var unsubscribe = null; unsubscribe = firebase .auth() .onAuthStateChanged((user) => { resolve(user); }, (error) => { reject(error); }, () => { unsubscribe(); }); }); } export const writeTaskOnFirebaseAsync = async (task) => { const user = await currentFirebaseUser(); var tasksReference = firebase .database() .ref(user.uid); const key = tasksReference .child('tasks') .push() .key; return await tasksReference .child(`tasks/${key}`) .update(task); }

Tabela 3.83 – Método writeTaskOnFirebaseAsync para criar Tasks

JavaScript import React, { Component } from 'react'; import { View, TextInput, Switch, Text, Button, StyleSheet } from 'react-native'; import { writeTaskOnFirebase, writeTaskOnFirebaseAsync } from '../services/FirebaseApi'; export default class Task extends Component { static navigationOptions = { title: 'Task' }

Page 92: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

91

state = { title: '', resume: '', priority: true, isDone: false }; render() { return ( <View style={styles.container}> <TextInput style={styles.input} placeholder='Title' value={this.state.title} onChangeText={(value) => this.setState({ title: value })} /> <TextInput style={[styles.input, styles.multilineInput]} placeholder='Resume' multiline={true} numberOfLines={4} value={this.state.resume} onChangeText={(value) => this.setState({ resume: value })} /> <View style={styles.switchContainer}> <Switch value={this.state.priority} onValueChange={(value) => this.setState({ priority: value })} value={this.state.priority} /> <Text style={styles.switchText}>Hight Priority</Text> </View> <View style={styles.switchContainer}> <Switch value={this.state.isDone} onValueChange={(value) => this.setState({ isDone: value })} value={this.state.isDone} /> <Text style={styles.switchText}>Is Done?</Text> </View> <Button style={styles.button} title='Save' onPress={async () => this._saveTaskAsync()} /> </View> ); } async _saveTaskAsync() { var task = { title: this.state.title, resume: this.state.resume, priority: this.state.priority, isDone: this.state.isDone }; try { await writeTaskOnFirebaseAsync(task); this.props.navigation.goBack(); } catch (error) { Alert.alert("Erro Saving", error.message); } } } const styles = StyleSheet.create({ container: { flex: 1, padding: 20,

Page 93: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

92

}, input: { marginBottom: 20 }, multilineInput: { height: 100 }, switchContainer: { flexDirection: 'row', alignItems: 'center', paddingBottom: 20 }, switchText: { marginLeft: 10, color: 'black', fontSize: 18 } });

Tabela 3.84 – Classe Task

JavaScript import App from './App'; import Login from './Login'; import Register from './Register'; import ToDoTasks from './ToDoTasks'; import DoneTasks from './DoneTasks'; import Task from './Task'; export { App, Login, Register, ToDoTasks, DoneTasks, Task }

Tabela 3.85 - Arquivo Screens com a página Task

JavaScript import { createStackNavigator, createTabNavigator } from 'react-navigation'; import { App, Login, Register, ToDoTasks, DoneTasks, Task } from '../screens/Screens'; import { Platform } from 'react-native'; const taskListTabNavigator = createTabNavigator({ pageToDoTasks: { screen: ToDoTasks, title: 'To Do' }, pageDoneTasks: { screen: DoneTasks, title: 'Done' } }); export default Routes = createStackNavigator( { pageApp: { screen: App }, pageLogin: { screen: Login }, pageRegister: { screen: Register }, pageTasksList: { screen: taskListTabNavigator, navigationOptions: { ...Platform.select({ ios: { title: 'Task List' }, android: {

Page 94: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

93

header: null } }) } }, pageTask: { screen: Task } }, { headerMode: 'screen' } );

Tabela 3.86 – Definição da rota para Task

JavaScript import React, { Component } from 'react'; import { Image, StyleSheet, View, TouchableOpacity } from 'react-native'; const imgCheckList = require('../assets/checklist.png'); const imgPlus = require('../assets/plus_64.png'); export default class ToDoTasks extends Component { static navigationOptions = { tabBarLabel: 'To Do', tabBarIcon: ({ tintColor }) => ( <Image source={imgCheckList} style={[styles.icon, { tintColor }]} /> ) } state = { tasks: [] } render() { return ( <View style={styles.container}> <TouchableOpacity style={styles.floatButton} onPress={() => this._goToTask()}> <Image source={imgPlus} style={styles.img} /> </TouchableOpacity> </View> ); } _goToTask() { this.props.navigation.navigate('pageTask'); } } const styles = StyleSheet.create({ container: { flex: 1, paddingLeft: 10, paddingRight: 10 }, icon: { width: 26, height: 26

Page 95: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

94

}, img: { width: 50, height: 50 }, floatButton: { position: 'absolute', right: 20, bottom: 20 } });

Tabela 3.87 – Navegando para tela Task

3.14 COMPONENTE DE LISTAGEM

Neste subcapítulo vamos codificar a leitura das tarefas do usuário autenticado

no Firebase. Vamos aproveitar e explorar um conceito muito importante do React: componentizar, ou seja, separar o nosso código o máximo que pudermos.

Vamos começar codificando um componente para nossa listagem de tarefas.

1. Com o nosso projeto aberto no VS Code, vamos criar o arquivo

TaskListView dentro da pasta src/components;

2. Vamos criar o esqueleto de nossa classe TaskListView e deixá-la de

acordo com o código apresentado na Tabela 3.88 - Criando o componente

TaskListView;

JavaScript import React, { Component } from 'react'; import { View, SectionList, Text, TouchableOpacity, StyleSheet } from 'react-native'; export default class TaskListView extends Component { } const styles = StyleSheet.create({ container: { flex: 1, flexDirection: 'column', paddingLeft: 10, paddingRight: 10 }, headerConteiner: { flex: 1, flexDirection: 'row', alignItems: 'center', backgroundColor: 'silver', borderRadius: 25, marginTop: 10 }, headerTagConteiner: {

Page 96: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

95

backgroundColor: 'gray', height: 35, width: 35, alignItems: 'center', justifyContent: 'center', borderRadius: 25 }, headerTagText: { color: '#FFF', fontSize: 22 }, headerText: { fontSize: 16, marginLeft: 10 }, itemConteiner: { flex: 1, flexDirection: 'column', backgroundColor: '#F3F2F0', marginTop: 5, padding: 10, height: 75 }, itemTextTitle: { fontSize: 22 } });

Tabela 3.88 - Criando o componente TaskListView

Por enquanto, importamos os componentes que utilizamos, definimos nossa

classe e criamos alguns estilos.

3. Vamos codificar o método render. Para facilitar nossa codificação vamos

dividir o método render em mais três trechos de código: métodos _renderSectionHeader, _renderItem e o próprio método render;

JavaScript ... _renderSectionHeader(sectionData) { return ( <View style={styles.headerConteiner}> <View style={styles.headerTagConteiner}> <Text style={styles.headerTagText}>{sectionData.section.title.substr(0, 1)}</Text> </View> <Text style={styles.headerText}>{sectionData.section.title}</Text> </View> ); } ...

Tabela 3.89 – Implementando a propriedade renderSectionHeader do componente SectionList

O método _renderSectionHeader representa o título das seções. Não

codificamos nada que ainda não estudamos no trecho de código apresentado na Tabela

3.89 – Implementando a propriedade renderSectionHeader do componente SectionList.

Page 97: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

96

A única observação é que no estilo hearderConteiner a propriedade flexDirections é

igual a row, ou seja, os componentes filhos serão organizados um ao lado do outro, na

horizontal.

JavaScript ... _renderItem(itemData) { return ( <TouchableOpacity> <View style={styles.itemConteiner}> <Text style={styles.itemTextTitle}>{itemData.item.title}</Text> <Text>{itemData.item.resume}</Text> </View> </TouchableOpacity> ); } ...

Tabela 3.90 – Implementando a propriedade renderItem do componente SectionList

O método _renderItem representa cada Task que será listada em nossa tela.

Também não temos nenhuma novidade que ainda não estudamos no trecho de código

apresentado na Tabela 3.90 – Implementando a propriedade renderItem do componente

SectionList.

JavaScript ... render() { return ( <SectionList renderSectionHeader={(section) => this.renderSectionHeader(section)} sections={[ { data: this.state.tasks.filter((data) => { return data.priority && !data.isDone }), key: "hightPriority", title: 'Hight Priority' }, { data: this.state.tasks.filter((data) => { return !data.priority && !data.isDone }), key: "lowPriority", title: 'Low Priority' }, ]} renderItem={(data) => this.renderItem(data)} /> ); } ...

Tabela 3.91 – Método render do componente TasListView

Nosso último método é o render. Neste método usamos o componente

SectionList que é o responsável em listar nossas Tasks. Codificamos três pontos

importantes no trecho de código acima. O primeiro ponto que codificamos é a

Page 98: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

97

propriedade renderSectionHeader do componente SectionList onde definimos como

será a apresentação do título das seções. A propriedade renderSectionHeader recebe

como parâmetro o método _renderSectionHeader. O segundo ponto que codificamos é

a propriedade sections que recebe como parâmetro um array. Esse array é definido

através de um filtro sobre as Tasks com alta prioridade e baixa prioridade. O último ponto

que codificamos é a propriedade renderItem onde definimos como será a apresentação

de cada Task. A propriedade renderItem recebe como parâmetro o método _renderItem.

Vamos aproveitar e deixar o esquema de import/export dos componentes.

Mesmo esquema que fizemos com as nossas páginas.

4. Vamos criar o arquivo Components.js na pasta src/components e

importar e exportar nosso componente TaskListView;

JavaScript import TaskListView from './TaskListView'; export { TaskListView }

Tabela 3.92 – Esquema de import/export de componentes

Agora precisamos recuperar as tarefas do Firebase.

5. Vamos abrir o arquivo FirebaseApi.js localizado dentro da pasta

src/services e criar o método readTasksFromFirebaseAsync;

JavaScript export const readTasksFromFirebaseAsync = async (listener) => { const user = await currentFirebaseUser(); var tasksReference = firebase .database() .ref(user.uid) .child('tasks'); tasksReference .on('value', (snapshot) => { var tasks = []; snapshot.forEach(function (element) { var task = element.val(); task.key = element.key; tasks.push(task); }); listener(tasks); }); }

Tabela 3.93 – Método para ler as Tasks no Firebase

Page 99: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

98

O método readTasksFromFirebaseAsync recebe um método como

parâmetro. O Firebase tem a inteligência de observar qualquer alteração que houver nas

Tasks e notificar o método passado como parâmetro. Essa notificação é realizada

através do método tasksReference.on(...).

6. O próximo passo é abrir nossa classe ToDoTasks.js, definir um state para

guardar a referência das Tasks e implementar os métodos para realizar a

leitura das Tasks;

JavaScript ... import { readTasksFromFirebaseAsync } from '../services/FirebaseApi'; ... export default class ToDoTasks extends Component { ... state = { tasks: [] } ... componentDidMount() { readTasksFromFirebaseAsync(this._fetchTasks.bind(this)); } _fetchTasks(tasks) { const tasksToDo = tasks.filter(t => !t.isDone); this.setState({ tasks: tasksToDo }); } } ...

Tabela 3.94 – Lendo as tarefas no método componentDidMount

O único ponto de destaque no trecho do código da Tabela 3.94 – Lendo as

tarefas no método componentDidMount é o método _fetchTasks que, ao receber as

tarefas repassadas pelo método readTaskFromFirebaseAsync, realiza um filtro

somente das tarefas que não estão concluídas. Esse procedimento se dá através do

código tasks.filter(t => !t.isDone).

7. Último passo é ajustar a página ToDoTasks, adicionar o componente

TaskListView e enviar a referência do state tasks. Vamos importar o

componente TaskListView e ajustar o método render.

JavaScript

Page 100: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

99

... import { TaskListView } from '../components/Components'; import { readTaskFromFirebaseAsync } from '../services/FirebaseApi'; ... export default class ToDoTasks extends Component { ... render() { return ( <View style={styles.container}> <TaskListView tasks={this.state.tasks} /> <TouchableOpacity style={styles.floatButton} onPress={() => this._goToTask()}> <Image source={imgPlus} style={styles.img} /> </TouchableOpacity> </View> ); } ...

Tabela 3.95 – Ajustando o método render da página ToDoTasks

Pronto! Agora é só testarmos.

Neste subcapítulo alteramos três classes. Vamos ver o resultado das classes

através da Tabela 3.96 – Método readTasksFromFirebaseAsync para ler as Tasks,

Tabela 3.97 - Componente TaskListView e Tabela 3.98 – Página ToDoTasks.

JavaScript import firebase from 'firebase'; const config = { apiKey: "AIzaSyDtVC3VQ1Z8XzQYDkWwnTOC_NFo8ny5c90", authDomain: "todomanager-5444a.firebaseapp.com", databaseURL: "https://todomanager-5444a.firebaseio.com", projectId: "todomanager-5444a", storageBucket: "todomanager-5444a.appspot.com", messagingSenderId: "254572727152" }; export const initializeFirebaseApi = () => firebase.initializeApp(config); export const createUserOnFirebaseAsync = async (email, password) => { const user = await firebase .auth() .createUserWithEmailAndPassword(email, password); return user; } export const signInOnFirebaseAsync = async (email, password) => { const user = await firebase .auth() .signInWithEmailAndPassword(email, password); return user; }

Page 101: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

100

export const currentFirebaseUser = () => { return new Promise((resolve, reject) => { var unsubscribe = null; unsubscribe = firebase .auth() .onAuthStateChanged((user) => { resolve(user); }, (error) => { reject(error); }, () => { unsubscribe(); }); }); } export const writeTaskOnFirebaseAsync = async (task) => { const user = await currentFirebaseUser(); var tasksReference = firebase .database() .ref(user.uid); const key = tasksReference .child('tasks') .push() .key; return await tasksReference .child(`tasks/${key}`) .update(task); } export const readTaskFromFirebaseAsync = async (listener) => { const user = await currentFirebaseUser(); var tasksReference = firebase .database() .ref(user.uid) .child('tasks'); tasksReference .on('value', (snapshot) => { var tasks = []; snapshot.forEach(function (element) { var task = element.val(); task.key = element.key; tasks.push(task); }); listener(tasks); }); }

Tabela 3.96 – Método readTasksFromFirebaseAsync para ler as Tasks

JavaScript import React, { Component } from 'react'; import { View, SectionList, Text, TouchableOpacity, StyleSheet } from 'react-native'; export default class TaskListView extends Component { _renderSectionHeader(sectionData) {

Page 102: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

101

return ( <View style={styles.headerConteiner}> <View style={styles.headerTagConteiner}> <Text style={styles.headerTagText}>{sectionData.section.title.substr(0, 1)}</Text> </View> <Text style={styles.headerText}>{sectionData.section.title}</Text> </View> ); } _renderItem(itemData) { return ( <TouchableOpacity> <View style={styles.itemConteiner}> <Text style={styles.itemTextTitle}>{itemData.item.title}</Text> <Text>{itemData.item.resume}</Text> </View> </TouchableOpacity> ); } render() { return ( <SectionList renderSectionHeader={(section) => this._renderSectionHeader(section)} sections={[ { data: this.props.tasks.filter((data) => { return data.priority }), key: "hightPriority", title: 'Hight Priority' }, { data: this.props.tasks.filter((data) => { return !data.priority }), key: "lowPriority", title: 'Low Priority' }, ]} renderItem={(data) => this._renderItem(data)} /> ); } } const styles = StyleSheet.create({ container: { flex: 1, flexDirection: 'column', paddingLeft: 10, paddingRight: 10 }, headerConteiner: { flex: 1, flexDirection: 'row', alignItems: 'center', backgroundColor: 'silver', borderRadius: 25, marginTop: 10 }, headerTagConteiner: { backgroundColor: 'gray', height: 35,

Page 103: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

102

width: 35, alignItems: 'center', justifyContent: 'center', borderRadius: 25 }, headerTagText: { color: '#FFF', fontSize: 22 }, headerText: { fontSize: 16, marginLeft: 10 }, itemConteiner: { flex: 1, flexDirection: 'column', backgroundColor: '#F3F2F0', marginTop: 5, padding: 10, height: 75 }, itemTextTitle: { fontSize: 22 } });

Tabela 3.97 - Componente TaskListView

JavaScript import React, { Component } from 'react'; import { Image, StyleSheet, View, TouchableOpacity } from 'react-native'; import { TaskListView } from '../components/Components'; import { readTaskFromFirebaseAsync } from '../services/FirebaseApi'; const imgCheckList = require('../assets/checklist.png'); const imgPlus = require('../assets/plus_64.png'); export default class ToDoTasks extends Component { static navigationOptions = { tabBarLabel: 'To Do', tabBarIcon: ({ tintColor }) => ( <Image source={imgCheckList} style={[styles.icon, { tintColor }]} /> ) } state = { tasks: [] } render() { return ( <View style={styles.container}> <TaskListView tasks={this.state.tasks} /> <TouchableOpacity style={styles.floatButton} onPress={() => this._goToTask()}> <Image source={imgPlus} style={styles.img} /> </TouchableOpacity> </View> ); }

Page 104: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

103

_goToTask() { this.props.navigation.navigate('pageTask'); } componentDidMount() { readTaskFromFirebaseAsync(this._fetchTasks.bind(this)); } _fetchTasks(tasks) { const tasksToDo = tasks.filter(t => !t.isDone); this.setState({ tasks: tasksToDo }); } } const styles = StyleSheet.create({ container: { flex: 1, paddingLeft: 10, paddingRight: 10 }, icon: { width: 26, height: 26 }, img: { width: 50, height: 50 }, floatButton: { position: 'absolute', right: 20, bottom: 20 } });

Tabela 3.98 – Página ToDoTasks

3.15 AJUSTANDO A LISTAGEM DONE

No subcapítulo anterior criamos nosso componente de listagem das tarefas e

ajustamos a listagem To Do. Neste subcapítulo vamos praticamente replicar o que

fizemos na classe ToDoTasks para a classe DoneTasks.

1. Vamos abrir nossa classe DoneTasks.js, definir um state para guardar a

referência das Tasks e implementar os métodos para realizar a leitura das

Tasks;

JavaScript ... import { TaskListView } from '../components/Components'; import { readTasksFromFirebaseAsync } from '../services/FirebaseApi'; ... export default class DoneTasks extends Component {

Page 105: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

104

... state = { tasks: [] } render() { return ( <View style={styles.container} > <TaskListView tasks={this.state.tasks} /> </View> ); } componentDidMount() { readTasksFromFirebaseAsync(this._fetchTasks.bind(this)); } _fetchTasks(tasks) { const tasksToDo = tasks.filter(t => t.isDone); this.setState({ tasks: tasksToDo }); } } ...

Tabela 3.99 – Lendo as tarefas no método componentDidMount

Assim como fizemos na classe ToDoTasks o método _fetchTasks também

realiza um filtro, mas desta vez realiza um filtro somente das tarefas que estão concluídas.

Esse procedimento se dá através do código tasks.filter(t => t.isDone).

Pronto! Agora é só testarmos, mas antes, vamos ver como ficou nossa classe

DoneTasks através da Tabela 3.100 – Página DoneTasks.

JavaScript import React, { Component } from 'react'; import { Image, StyleSheet, View } from 'react-native'; import { TaskListView } from '../components/Components'; import { readTasksFromFirebaseAsync } from '../services/FirebaseApi'; const imgDone = require('../assets/done.png'); export default class DoneTasks extends Component { static navigationOptions = { tabBarLabel: 'Done', tabBarIcon: ({ tintColor }) => ( <Image source={imgDone} style={[styles.icon, { tintColor }]} /> ) } state = { tasks: [] }

Page 106: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

105

render() { return ( <View style={styles.container} > <TaskListView tasks={this.state.tasks} /> </View> ); } componentDidMount() { readTasksFromFirebaseAsync(this._fetchTasks.bind(this)); } _fetchTasks(tasks) { const tasksToDo = tasks.filter(t => t.isDone); this.setState({ tasks: tasksToDo }); } } const styles = StyleSheet.create({ container: { flex: 1, paddingLeft: 10, paddingRight: 10 }, icon: { width: 26, height: 26 }, img: { width: 50, height: 50 } });

Tabela 3.100 – Página DoneTasks

3.16 ATUALIZANDO UMA TAREFA

Falta muito pouco para deixarmos nossa aplicação funcional. Neste

subcapítulo vamos alterar a tela que incluir uma nova tarefa para também alterar uma

tarefa existente.

1. Vamos abrir o arquivo FirebaseApi.js localizado dentro da pasta

src/services/ e alterar o método writeTaskOnFirebase;

JavaScript export const writeTaskOnFirebaseAsync = async (task) => { const user = await currentFirebaseUser(); var tasksReference = firebase .database() .ref(user.uid); const key = task.key ? task.key : tasksReference .child('tasks')

Page 107: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

106

.push() .key; return await tasksReference .child(`tasks/${key}`) .update(task); }

Tabela 3.101 – Método para alterar Task no Firebase

O método writeTaskOnFirebase recebe o parâmetro task – que é

representado por um json – e repassa esse parâmetro invocando o método update da

biblioteca do Firebase, mas desta vez, fazemos uma verificação se o objeto task possui

a propriedade key definida. Se a propriedade key estiver definida sabemos que se trata

de uma alteração e usaremos o valor desta propriedade como referência. Caso contrário,

solicitaremos uma nova referência para o Firebase.

2. Dando continuidade em nossa codificação, vamos abrir o arquivo

ToDoTask.js e DoneTasks localizados na pasta src/screens/. Vamos

localizar o componente TaskListView e passar a referência do navegador

como parâmetro;

JavaScript ... render() { return ( ... <TaskListView tasks={this.state.tasks} navigation={this.props.navigation} /> ... ); } ...

Tabela 3.102 – Passando a referência do navegador

3. Agora, vamos abrir o componente TaskListView e implementar o clique

sobre a tarefa;

JavaScript ... _renderItem(itemData) { return ( <TouchableOpacity onPress={() => this._onClickTask(itemData.item)}> <View style={styles.itemConteiner}> <Text style={styles.itemTextTitle}>{itemData.item.title}</Text> <Text>{itemData.item.resume}</Text> </View> </TouchableOpacity> ); }

Page 108: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

107

_onClickTask(task) { const { navigate } = this.props.navigation; navigate('pageTask', { task }); } ...

Tabela 3.103 – Definindo a classe Task

Fizemos duas alterações importantes em nosso componente TaskListView. A primeira alteração foi criar o método _onClickTask que navega para a página Task

passando como parâmetro a tarefa do item que clicamos. A segunda alteração foi

executar o método _onClickTask quando clicamos na tarefa.

4. Por último, vamos ajustar nossa tela Task para recuperar a tarefa passada

como parâmetro;

JavaScript ... export default class Task extends Component { ... state = { key: '', title: '', resume: '', priority: true, isDone: false }; constructor(props) { super(props); try { const task = this.props.navigation.state.params.task; this.state = { key: task.key, title: task.title, resume: task.resume, priority: task.priority, isDone: task.isDone }; } catch (error) { } } ... async _saveTaskAsync() { var task = { key: this.state.key, title: this.state.title, resume: this.state.resume, priority: this.state.priority, isDone: this.state.isDone };

Page 109: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

108

try { await writeTaskOnFirebaseAsync(task); this.props.navigation.goBack(); } catch (error) { Alert.alert("Erro Saving", error.message); } } } ...

Tabela 3.104 – Recuperando uma Task passada como parâmetro

No construtor da página recuperamos a objeto Task passado como parâmetro

e no método _saveTaskAsync repassamos para o Firebase a Task recebida.

Neste subcapítulo alteramos cinco arquivos. Vamos ver o resultado desse

trabalho através dos trechos de códigos apresentados na Tabela 3.105 – Classe de

serviço FirebaseApi, Tabela 3.106 – Página ToDoTask, Tabela 3.107 – Página

DoneTasks, Tabela 3.108 – Componente TaskListView e Tabela 3.109 – Págna Task.

JavaScript import firebase from 'firebase'; const config = { apiKey: "AIzaSyDtVC3VQ1Z8XzQYDkWwnTOC_NFo8ny5c90", authDomain: "todomanager-5444a.firebaseapp.com", databaseURL: "https://todomanager-5444a.firebaseio.com", projectId: "todomanager-5444a", storageBucket: "todomanager-5444a.appspot.com", messagingSenderId: "254572727152" }; export const initializeFirebaseApi = () => firebase.initializeApp(config); export const createUserOnFirebaseAsync = async (email, password) => { const user = await firebase .auth() .createUserWithEmailAndPassword(email, password); return user; } export const signInOnFirebaseAsync = async (email, password) => { const user = await firebase .auth() .signInWithEmailAndPassword(email, password); return user; } export const currentFirebaseUser = () => { return new Promise((resolve, reject) => { var unsubscribe = null; unsubscribe = firebase

Page 110: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

109

.auth() .onAuthStateChanged((user) => { resolve(user); }, (error) => { reject(error); }, () => { unsubscribe(); }); }); } export const writeTaskOnFirebaseAsync = async (task) => { const user = await currentFirebaseUser(); var tasksReference = firebase .database() .ref(user.uid); const key = task.key ? task.key : tasksReference .child('tasks') .push() .key; return await tasksReference .child(`tasks/${key}`) .update(task); } export const readTasksFromFirebaseAsync = async (listener) => { const user = await currentFirebaseUser(); var tasksReference = firebase .database() .ref(user.uid) .child('tasks'); tasksReference .on('value', (snapshot) => { var tasks = []; snapshot.forEach(function (element) { var task = element.val(); task.key = element.key; tasks.push(task); }); listener(tasks); }); }

Tabela 3.105 – Classe de serviço FirebaseApi

JavaScript import React, { Component } from 'react'; import { Image, StyleSheet, View, TouchableOpacity } from 'react-native'; import { TaskListView } from '../components/Components'; import { readTasksFromFirebaseAsync } from '../services/FirebaseApi'; const imgCheckList = require('../assets/checklist.png'); const imgPlus = require('../assets/plus_64.png'); export default class ToDoTasks extends Component {

Page 111: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

110

static navigationOptions = { tabBarLabel: 'To Do', tabBarIcon: ({ tintColor }) => ( <Image source={imgCheckList} style={[styles.icon, { tintColor }]} /> ) } state = { tasks: [] } render() { return ( <View style={styles.container}> <TaskListView tasks={this.state.tasks} navigation={this.props.navigation} /> <TouchableOpacity style={styles.floatButton} onPress={() => this._goToTask()}> <Image source={imgPlus} style={styles.img} /> </TouchableOpacity> </View> ); } _goToTask() { this.props.navigation.navigate('pageTask'); } componentDidMount() { readTasksFromFirebaseAsync(this._fetchTasks.bind(this)); } _fetchTasks(tasks) { const tasksToDo = tasks.filter(t => !t.isDone); this.setState({ tasks: tasksToDo }); } } const styles = StyleSheet.create({ container: { flex: 1, paddingLeft: 10, paddingRight: 10 }, icon: { width: 26, height: 26 }, img: { width: 50, height: 50 }, floatButton: { position: 'absolute', right: 20, bottom: 20 } });

Tabela 3.106 – Página ToDoTask

Page 112: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

111

JavaScript import React, { Component } from 'react'; import { Image, StyleSheet, View } from 'react-native'; import { TaskListView } from '../components/Components'; import { readTasksFromFirebaseAsync } from '../services/FirebaseApi'; const imgDone = require('../assets/done.png'); export default class DoneTasks extends Component { static navigationOptions = { tabBarLabel: 'Done', tabBarIcon: ({ tintColor }) => ( <Image source={imgDone} style={[styles.icon, { tintColor }]} /> ) } state = { tasks: [] } render() { return ( <View style={styles.container} > <TaskListView tasks={this.state.tasks} navigation={this.props.navigation} /> </View> ); } componentDidMount() { readTasksFromFirebaseAsync(this._fetchTasks.bind(this)); } _fetchTasks(tasks) { const tasksToDo = tasks.filter(t => t.isDone); this.setState({ tasks: tasksToDo }); } } const styles = StyleSheet.create({ container: { flex: 1, paddingLeft: 10, paddingRight: 10 }, icon: { width: 26, height: 26 }, img: { width: 50, height: 50 } });

Tabela 3.107 – Página DoneTasks

JavaScript import React, { Component } from 'react';

Page 113: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

112

import { View, SectionList, Text, TouchableOpacity, StyleSheet } from 'react-native'; export default class TaskListView extends Component { _renderSectionHeader(sectionData) { return ( <View style={styles.headerConteiner}> <View style={styles.headerTagConteiner}> <Text style={styles.headerTagText}>{sectionData.section.title.substr(0, 1)}</Text> </View> <Text style={styles.headerText}>{sectionData.section.title}</Text> </View> ); } _renderItem(itemData) { return ( <TouchableOpacity onPress={() => this._onClickTask(itemData.item)}> <View style={styles.itemConteiner}> <Text style={styles.itemTextTitle}>{itemData.item.title}</Text> <Text>{itemData.item.resume}</Text> </View> </TouchableOpacity> ); } _onClickTask(task) { const { navigate } = this.props.navigation; navigate('pageTask', { task }); } render() { return ( <SectionList renderSectionHeader={(section) => this._renderSectionHeader(section)} sections={[ { data: this.props.tasks.filter((data) => { return data.priority }), key: "hightPriority", title: 'Hight Priority' }, { data: this.props.tasks.filter((data) => { return !data.priority }), key: "lowPriority", title: 'Low Priority' }, ]} renderItem={(data) => this._renderItem(data)} /> ); } } const styles = StyleSheet.create({ container: { flex: 1, flexDirection: 'column', paddingLeft: 10, paddingRight: 10 },

Page 114: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

113

headerConteiner: { flex: 1, flexDirection: 'row', alignItems: 'center', backgroundColor: 'silver', borderRadius: 25, marginTop: 10 }, headerTagConteiner: { backgroundColor: 'gray', height: 35, width: 35, alignItems: 'center', justifyContent: 'center', borderRadius: 25 }, headerTagText: { color: '#FFF', fontSize: 22 }, headerText: { fontSize: 16, marginLeft: 10 }, itemConteiner: { flex: 1, flexDirection: 'column', backgroundColor: '#F3F2F0', marginTop: 5, padding: 10, height: 75 }, itemTextTitle: { fontSize: 22 } });

Tabela 3.108 – Componente TaskListView

JavaScript import React, { Component } from 'react'; import { View, TextInput, Switch, Text, Button, StyleSheet } from 'react-native'; import { writeTaskOnFirebaseAsync } from '../services/FirebaseApi'; export default class Task extends Component { static navigationOptions = { title: 'Task' } state = { key: '', title: '', resume: '', priority: true, isDone: false }; constructor(props) { super(props); try { const task = this.props.navigation.state.params.task;

Page 115: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

114

this.state = { key: task.key, title: task.title, resume: task.resume, priority: task.priority, isDone: task.isDone }; } catch (error) { } } render() { return ( <View style={styles.container}> <TextInput style={styles.input} placeholder='Title' value={this.state.title} onChangeText={(value) => this.setState({ title: value })} /> <TextInput style={[styles.input, styles.multilineInput]} placeholder='Resume' multiline={true} numberOfLines={4} value={this.state.resume} onChangeText={(value) => this.setState({ resume: value })} /> <View style={styles.switchContainer}> <Switch value={this.state.priority} onValueChange={(value) => this.setState({ priority: value })} value={this.state.priority} /> <Text style={styles.switchText}>Hight Priority</Text> </View> <View style={styles.switchContainer}> <Switch value={this.state.isDone} onValueChange={(value) => this.setState({ isDone: value })} value={this.state.isDone} /> <Text style={styles.switchText}>Is Done?</Text> </View> <Button style={styles.button} title='Save' onPress={async () => this._saveTaskAsync()} /> </View> ); } async _saveTaskAsync() { var task = { key: this.state.key, title: this.state.title, resume: this.state.resume, priority: this.state.priority, isDone: this.state.isDone }; try { await writeTaskOnFirebaseAsync(task); this.props.navigation.goBack(); } catch (error) { Alert.alert("Erro Saving", error.message); } } }

Page 116: Introdução ao React Native · Introdução ao React Native Antonio Lopes Jr React Native, 1ª Versão Sem Revisão

115

const styles = StyleSheet.create({ container: { flex: 1, padding: 20, }, input: { marginBottom: 20 }, multilineInput: { height: 100 }, switchContainer: { flexDirection: 'row', alignItems: 'center', paddingBottom: 20 }, switchText: { marginLeft: 10, color: 'black', fontSize: 18 } });

Tabela 3.109 – Págna Task

4 REFERÊNCIAS BIBLIOGRÁFICAS

NOVICK, Vladimir. React Native – Building Mobile Apps with JavaScript. Editora Packt

Publishing Limited. Primeira Edição, Agosto de 2017, 434 páginas.

KHO, Richard. React Native By Example. Editora Packt Publishing Limited. Primeira

Edição, Abril de 2017, 414 páginas.

SANT ANA, Jorge e DAMASCENO, Jamilton. Desenvolvedor Multiplataforma

Android/iOS com React Native e Redux. Disponível em

<https://www.udemy.com/desenvolvedor-multiplataforma-androidios-com-react-e-

redux/learn/v4/t/lecture/6275548?start=0>. Acesso em 20 de Setembro de 2017.

React Navigation Docs. Hello Mobile Navigation. Disponível em

<https://reactnavigation.org/docs/intro/>. Acesso em 9 de Outubro de 2017.