Tutorial de ReactJS com Node.js – Parte 4 – LuizTools
Tutorial de ReactJS com Node.js - Parte 4
Escrito por Luiz Duarte em 21/06/2020
E chegamos à quarta parte da minha série sobre como construir aplicações ReactJS no front-end usando Node.js no backend. Para quem está chegando agora, não comece por esse post, mas ao invés disso, use os links abaixo para conhecer os outros capítulos da série.
E agora, continuando o que estávamos vendo, recém havíamos usado a function useEffect do React para carregar uma API de estados do Brasil e imprimir o retorno no console, lembra?
O próximo passo é usar os objetos JSON retornados por ela, que contém os estados do Brasil, para popular dinamicamente o select no nosso formulário HTML.
E é por aí que começaremos o artigo de hoje!
Alterando o HTML 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:
import React, { useEffect, useState } from 'react'; import Header from '../Header'; import axios from 'axios';
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 pra dentro deste estado. Soou estranho, mas você entendeu, né?
function Form(){ const [estados, setEstados] = useState([]); useEffect(() => { axios.get('http://localhost:3030/estados').then(response => { setEstados(response.data); }) }, []);
const [estados, setEstados] = useState([]);
axios.get('http://localhost:3030/estados').then(response => {
setEstados(response.data);
Certo, com isso, o objeto estados será um array populado pela API na primeira vez que a tela de cadastro for carregada. Para usá-lo vamos escrever código JavaScript como lógica de interface, de forma muito semelhante a como é feito em PHP, JSP e até mesmo Node.js com view-engine EJS.
<div> <label>UF: <select name="cmbUF" id="cmbUF" > <option value="0">Selecione uma opção</option> {estados.map(estado => (<option key={estado.id} value={estado.id}>{estado.uf}</option>))} </select> </label> </div>
<label>UF:
<select name="cmbUF" id="cmbUF" >
<option value="0">Selecione uma opção</option>
{estados.map(estado => (<option key={estado.id} value={estado.id}>{estado.uf}</option>))}
Atenção ao fato deste código ser apenas um pedaço do seu HTML, onde abaixo do option fixo, vamos usar um JavaScript map que nada mais é do que uma função que percorre todos os elementos de um array, executando uma outra função passada por parâmetro. Neste caso, esta função mais interna devolve um HTML com id e UF do estado.
Atenção: a propriedade key é usada pelo React e não é obrigatória, mas aconselhável, para que ele consiga manipular melhor os componentes gerados dinamicamente em iterações como essa.
Se você voltar ao navegador agora, vai ver que ao clicar no mesmo select de antes, agora ele estará populado conforme o que retorna na API.
Legal, não? Isso abre inúmeras possibilidades de campos com HTML dinâmico, montado a partir do retorno de APIs do backend.
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 estado e uma nova função que vai ser disparada toda vez que um campo for alterado, dentro da função principal do Form.js.
const [campos, setCampos] = useState({ txtNome: '', txtIdade: 0, cmbUF: '0' }); function handleInputChange(event){ campos[event.target.name] = event.target.value; setCampos(campos); }
const [campos, setCampos] = useState({
txtNome: '',
txtIdade: 0,
cmbUF: '0'
function handleInputChange(event){
campos[event.target.name] = event.target.value;
setCampos(campos);
O useState não é novidade, já tivemos de usar ele antes, mas desta vez, o estado armazenará um objeto em memória que representa os campos do formulário. Repare como coloquei o mesmo name de cada campo do form HTML como propriedades deste estado. isso vai ser útil na função a seguir.
A function handleInputChange irá ser disparada toda vez que um campo do formulário for alterado. Ela recebe um objeto event por parâmetro que, dentre suas várias propriedades tem o target, que é o campo que originou o evento. Com este target, conseguimos descobrir o name e o value atualizado do mesmo.
Cada vez que essa function for disparada, vamos chamar o setCampos atualizando uma propriedade dinamicamente com base no event.target.name e o seu valor com o event.target.value. Caso alguma parte esteja confusa para você, sugiro incluir alguns console.log em event.target, para que você entenda o que vai acontecer a seguir.
Ok, preparamos o terreno para a leitura dos campos, agora falta associarmos a function handleInputChange a cada um dos componentes do formulário. Todos eles possuem uma propriedade onChange, que você deve preencher com o nome da função. Abaixo, apenas o exemplo do input de nome, preencha também para o input de idade e o select de UF.
<input type="text" name="txtNome" id="txtNome" onChange={handleInputChange} />
E para ver se nossos campos foram lidos corretamente a cada modificação, ou seja, se o estado dos campos está sendo monitorado corretamente, vamos criar uma function para mapear a submissão do formulário:
function handleFormSubmit(event){ event.preventDefault(); console.log(campos); }
function handleFormSubmit(event){
console.log(campos);
Essa função é bem simples, além de imprimir no console o campos mapeados, ela previne o comportamento padrão do formulário de acontecer. Isso porque, por padrão, o HTML FORM tem uma série de comportamentos ligados à sua submissão como enviar todos a página para o servidor, mas não queremos isso.
Essa função deve ser adicionada no campo onSubmit da tag FORM do seu HTML, como abaixo.
Agora, ao rodar a nossa aplicação ReactJS, preencher os campos do formulário e clicar no botão de Salvar, o console do navegador deve exibir o objeto JSON dos campos mapeados.
Salvando o cadastro
Agora estamos muito perto de finalizar a parte de salvar os dados deste formulário. O React 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 em relação ao React. Nos tutoriais abaixo você aprenda como modificar esta API para o seu banco favorito:
//api-cadastro.js var http = require('http'); const express = require('express'); const app = express(); const bodyParser = require('body-parser'); app.use(require("cors")()); app.use(express.urlencoded({ extended: true })); app.use(express.json()); app.get('/', (req, res, next) => { res.json({message: "Tudo ok por aqui!", dados: cadastros}); }) const cadastros = []; app.post('/cadastro', (req, res, next) => { console.log("Cadastro recebido!"); //salva no banco de dados cadastros.push({ nome: req.body.txtNome, idade: parseInt(req.body.txtIdade), uf: req.body.cmbUF }); res.json({message: "Tudo ok por aqui!", dados: cadastros}); }) var server = http.createServer(app); server.listen(3031); console.log("Servidor escutando na porta 3031...")
//api-cadastro.js
app.use(require("cors")());
res.json({message: "Tudo ok por aqui!", dados: cadastros});
const cadastros = [];
app.post('/cadastro', (req, res, next) => {
console.log("Cadastro recebido!");
//salva no banco de dados
cadastros.push({
nome: req.body.txtNome,
idade: parseInt(req.body.txtIdade),
uf: req.body.cmbUF
server.listen(3031);
console.log("Servidor escutando na porta 3031...")
Para que esta API funcione, você primeiro tem de instalar as dependências abaixo:
npm install http express cors
E ao executar com "node api-cadastro", ela ficará escutando na porta 3031, que é para não ter conflito com a outra API e a própria aplicação ReactJS.
Agora, voltando ao ReactJS, já temos praticamente tudo pronto para enviar os dados do formulário para essa API. Basta modificar a nossa function de handleFormSubmit para que pegue os campos e execute um POST via Axios na nossa API de cadastro.
function handleFormSubmit(event){ event.preventDefault(); axios.post('http://localhost:3031/cadastro', campos).then(response => { alert(response.data.dados.length + ' cadastros!'); }) }
axios.post('http://localhost:3031/cadastro', campos).then(response => {
alert(response.data.dados.length + ' cadastros!');
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.
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!
Quer aprender a criar uma aplicação que envia emails com ReactJS e Node.js? Leia este outro tutorial.