Introdução ao React Native – Parte 5

E chegamos à quinta parte desta que já é uma das maiores séries aqui do blog, introduzindo os leitores à plataforma de construção de apps nativos, Android e iOS, React Native.

No capítulo anterior, terminamos de construir a interface de um formulário de cadastro com dois novos desafios pela frente. Um deles, o de carregar dinamicamente os estados brasileiros a partir de um banco de dados remoto, para popular uma lista de seleção. O segundo desafio, o de salvar os dados deste cadastro em um banco de dados remoto.

Em ambos os casos, teremos de aprender como consumir e enviar dados para web APIs, que são a camada intermediária que deve existir entre mobile apps e bancos de dados remotos. Ou seja, nesta nova etapa, vamos mexer um pouco em backend!

Consumindo uma Web API

A ideia aqui é carregar as UFs a partir de uma Web API. O que vamos fazer funciona para qualquer tecnologia que funcione seguindo o protocolo REST, falando de maneira mais simples, que converse através de requisições HTTP e retorne JSON como resultado.

Como exemplo, deixo para você uma web API muito simples, que retorna um array estático de estados, mas que muito bem poderia estar buscando de um banco de dados como MongoDB, MySQL ou MS SQL Server.

Abra outra janela do terminal, instale as dependências com o comando abaixo.

E deixe esta API rodando na sua máquina (node api-estados). Teste acessando http://localhost:3030/estados no navegador. Deve listar os estados em um array de objetos JavaScript.

Estados no Browser
Estados no Browser

Para que nosso app React Native possa chamar o backend que subimos, vamos instalar mais um pacote em nossa aplicação, o Axios, que é o cliente HTTP mais popular para Node.js.

Esse pacote vai permitir que muito facilmente a gente consuma serviços na web, como o de estados. Para usarmos este cliente HTTP, primeiro devemos importá-lo na página Form.js, como abaixo.

Note que além da importação do axios em si, importei uma função do React chamada useEffect. Essa função é usada para controlar a execução de outras funções que viermos a criar baseada em gatilhos. Embora existam outras maneiras de executar funções (vimos uma lá atrás, para um contador, lembra?), o uso do useEffect é recomendado para ter mais controle da sua aplicação React.

O useEffect funciona da seguinte forma: o primeiro parâmetro é a função que queremos executar, e o segundo, os gatilhos de execução (array). Um gatilho de execução é um outro objeto que, quando alterado, vai disparar o efeito/função. Caso você não passe nenhum objeto como gatilho, o efeito acontecerá somente uma vez quando a página for renderizada pela primeira vez, que é o que usaremos abaixo.

O objeto axios tem uma function get que serve para obter dados de uma web API externa, bastando passar o endereço da mesma por parâmetro. Opa, você reparou o endereço que coloquei ali não tem nada a ver com o endereço em que subimos a API de estados (localhost:3030)?

Isso porque o smartphone considera localhost ele próprio, e não a sua máquina de desenvolvimento e se você colocar pro axios chamar uma API em localhost, vai dar Network Error no Expo. Aquele endereço que usei ali é o fornecido pelo Metro Bundler, no canto inferior esquerdo, um pouco acima do QRCode, apenas usando a mesma porta que subimos nossa API ao invés da sugerida por ele.

Endereço Metro Bundler
Endereço Metro Bundler

Aqui temos dois pontos de atenção. O primeiro, que devemos alterar este endereço quando nosso app for enviado para uma loja de apps. Neste caso ele deverá apontar para a URL de produção da sua web API. O segundo ponto de atenção é que 192.168.0.103 é o endereço da minha máquina de desenvolvimento, na minha rede, então certifique-se de usar o endereço fornecido no seu Metro Bundler, ao invés de copiar o meu.

Dito isso, por enquanto, nosso efeito apenas imprime no console a resposta da requisição à API, apenas para me certificar de que está funcionando.

Estados no Terminal
Estados no Terminal

Vamos usar esse retorno agora.

Alterando o picker dinamicamente

Para que consigamos usar o array de estados para alterar o HTML da página, precisamos criar um novo estado para armazenar esse array, parecido com o que fizemos lá no início desta série com a variável contador. Na verdade essa prática de lidar com estados é regra no React quando precisamos persistir informações entre as requisições da página.

O primeiro passo, é mexer nos nossos imports do Form.js, para carregar a função useState:

O próximo passo, é usar esta função mais abaixo, dentro da função principal desta página, para criar um estado com um array vazio e, quando o efeito for disparado, carregar o array de estados que a API retornou pra dentro deste state do React. Tive de fazer uma pequena transformação com a function map, por exigência do nosso componente de Picker.

Certo, com isso, o objeto ufs será um array populado pela API na primeira vez que a tela de cadastro for carregada. Como o mesmo objeto está sendo referenciado na propriedade items do Picker, ele automaticamente já estará sendo carregado no componente, como se ele fosse estático como era antes.

Obviamente, para garantir que de fato estamos listando os ufs da API e não aquele array constante que tínhamos antes, remova-o do seu código se ainda não o fez.

Lendo os campos do formulário

E agora que temos o nosso formulário construído, chegou a hora de programar o clique do nosso botão de Salvar, certo?

Antes que a gente possa querer salvar alguma coisa, vamos precisar mapear/ler os estados dos campos do formulário, para que quando eles sejam alterados, a gente tenha o estado deles atualizado. Para isso, vamos criar um novo par estado/função para cada campo, visando mapear corretamente o estados do formulário. O useState não é novidade, já tivemos de usar ele antes.

Agora, para cada um dos campos que temos, vamos criar funções de manipulação do evento change dos mesmos.

A function handleNameChange irá ser disparada toda vez que o campo nome do formulário for alterado e assim por diante. Ela recebe uma string name por parâmetro, sendo o comportamento padrão dos InputText, por isso que no caso do handleAgeChange, eu faço a conversão para inteiro. Cada vez que uma dessas functions for disparada, vamos chamar a function de set do estado correspondente.

Ok, preparamos o terreno para a leitura dos campos, agora falta associarmos  a function de handle a cada um dos componentes do formulário. Todos os InputText possuem uma propriedade onChangeText, que você deve preencher com o nome da função. Enquanto isso, o Picker possui um onValueChange.

Se estas últimas três etapas estão um pouco confusas para você, experimente colocar um console.log em cada uma das funções handle, para ver no console os valores sendo lidos em tempo real.

E para ver se todos nossos campos foram lidos corretamente ao clicar no botão de Salvar, vamos criar uma function para mapear a submissão do formulário:

Essa função é bem simples, apenas imprime no console o campos mapeados. Essa função deve ser adicionada na propriedade onPress do nosso TouchableOpacity.

Agora, ao atualizar a nossa aplicação React Native, preencher os campos do formulário e clicar no botão de Salvar, o console deve exibir o objeto JSON dos campos mapeados.

Demais, não?

Salvando o cadastro

Agora estamos muito perto de finalizar a parte de salvar os dados deste formulário. O React Native cuida da parte de front-end e, uma vez que o banco de dados é responsabilidade do backend, vamos ter de pegar estes dados mapeados a partir do formulário e enviar para uma web API realizar o salvamento.

Abaixo, você tem um exemplo de API de cadastro fake, que não salva em banco de dados, mas na memória dela própria, mas que você pode usar para avançar neste tutorial sem eu ter de explicar como funciona acesso a dados em Node.js, visto que não muda nada independente do nosso frontend React Native. Nos tutoriais abaixo você aprenda como modificar esta API para o seu banco favorito:

Para que esta API funcione, você primeiro tem de instalar as dependências abaixo:

E ao executar com “node api-cadastro”, ela ficará escutando na porta 3031, que é para não ter conflito com a outra API (de estados). Experimente acessar localhost:3031 no navegador para ver os cadastros já existentes e até a usar o POSTMAN para fazer uns cadastros manualmente e garantir que tudo está funcionando como deveria.

Agora, voltando ao React Native, já temos praticamente tudo pronto para enviar os dados do formulário para essa API. Basta modificar a nossa function de handleButtonPress para que pegue os campos e execute um POST via Axios na nossa API de cadastro.

Repare que novamente usei o endereço 192.168.0.103 ao invés de localhost, sendo este o endereço que o Metro Bundler informa para mim. Consulte a sua instância do Metro Bundler no navegador para ver o endereço que você deve usar.

O resultado, é que você pode preencher o formulário e, ao clicar em salvar, os campos serão enviados para a API, que vai salvar o objeto cadastro em memória e retornar um array ‘dados’ que estamos usando apenas para alertar ao usuário que está funcionando.

Cadastro funcionando
Cadastro funcionando

Você pode acessar a API de cadastro no seu navegador também, via http://localhost:3031/ que ela deve listar todos os cadastros atualmente na sua memória.

Reitero que, como não possuo o intuito de ensinar toda a parte de cadastro no banco de dados, usamos esta API fake que você facilmente pode modificar ou usar outra que já possua, modificando levemente a chamada via Axios que POSTará os dados nela.

E por hoje é só, espero que tenha gostado desta série até o momento!

Gostou do tutorial de hoje? Conheça meu curso online de Node.js clicando no banner abaixo.

Curso Node.js e MongoDB