Seguindo com a terceira parte do projeto que construí na formação React da Rocketseat, um projeto de duas páginas/telas, onde uma tela contém o timer, e a outra tela contém o histórico dos ciclos realizados.
Nesta terceira parte do projeto vamos focar no formulário, validação e desempenho.
Caso queira adquirir os cursos da Rocketseat com o meu cupom de desconto Acesse esse link
Links úteis:
Capítulos:
- 1 - Controlled vs Uncontrolled
- 2 - O melhor dos dois mundos com React Hook Form
- 3 - Usando React Hook Form
- 4 - Validação com Zod
- 5 - Validação com o botão habilitado
- 6 - TypeScript no Formulário
- 7 - Resetando o Formulário
1 - Controlled vs Uncontrolled
Neste conteúdo vamos entender como podemos criar bons formulários em React.
Olhando o nosso formulário da página Home temos o campo onde colocamos o nome da tarefa e outro campo onde informamos por quanto tempo iremos trabalhar nessa tarefa. E, a primeira coisa que precisamos é de validação nesses campos, para que o usuário não faça o submit desse formulário sem preencher esses campos, ou preenchendo com o valor errado.
Outra coisa é o botão que fica ativo somente quando todos os campos estiverem preenchidos. Então, precisamos monitorar de alguma forma se o usuário está preenchendo, se já preencheu esses campos, podemos dizer em tempo real, para só depois habilitar o botão.
Há duas formas de trabalhar com formulários, a forma controlada e a forma não controlada (Controlled / Uncontrolled), e é muito importante entender esses dois termos, porque eles têm muito a ver como o React funciona.
A forma controlada (Controlled) é sobre manter em tempo real o estado, a informação que o usuário insere na nossa aplicação numa variável do componente. Então há todo momento que o usuário estiver digitando no input, o estado é atualizado com a nova informação, assim sempre teremos o valor mais atual do que o usuário digitou.
Estamos falando de formulário, mas isso pode ser usado em qualquer lugar que tenha um input.
Um exemplo fazendo da forma controlada:
Como temos esse valor em tempo real, a gente consegue facilmente ter acesso a esse valor no momento de fazer o submit. E, facilmente, conseguimos refletir visualmente alterações na interface, baseado no valor desses inputs.
Um exemplo disso é quando queremos habilitar o botão apenas quando o valor da tarefa esteja preenchido:
Então Controlled Components dentro do React, ou seja, qualquer componente que seja monitorado em tempo real o input do usuário, traz muita fluidez para mostrar ou deixar de mostrar algo na interface da aplicação, baseado nesse input do usuário.
O lado negativo do componente controlado
Toda vez que a gente faz uma atualização de estado, a gente provoca uma nova renderização, ou seja, toda vez que o setTask é chamado por qualquer motivo, o React precisa recalcular todo o conteúdo do componente, do estado que mudou. Isso de recalcular todo o conteúdo do componente, não necessariamente é lento, mas se a interface for muito complexa, com muita informação, pode, sim, virar um gargalo. 
Então em alguns casos, lidar com formulários desta maneira controlada, pode ser um problema para a aplicação em questão de desempenho. Na maioria das vezes não vai ser um problema, mas em alguns momentos, vai ser.
A forma Uncontrolled
Como seria então a forma Uncontrolled?
Desta forma Uncontrolled a gente acaba perdendo a fluidez.
Quando é indicado cada?
- 
Controlled (Monitorado em tempo real):- formulários simples com poucos campos;
- interface simples;
- formulário de login, por exemplo;
 
- 
Uncontrolled (Não Monitorado):- formulários gigantes com muitos campos;
 
  
  
  2 - O melhor dos dois mundos com React Hook Form 
Nessa parte vamos utilizar a biblioteca React Hook Form. Ela nos ajuda a trabalhar com Controlled Components sem perder o desempenho, evitando renderizações desnecessárias.
O React Hook Form é uma biblioteca popular para gerenciar formulários em React por várias razões importantes:
- Performance otimizada- Minimiza a quantidade de re-renderizações usando um sistema de registro de campos não controlados, o que melhora significativamente a performance comparado com formulários controlados tradicionais.
- Menos código- Reduz significativamente a quantidade de código necessário para gerenciar formulários. Você não precisa criar estados para cada campo nem gerenciar suas atualizações manualmente.
- 
Validação eficiente- Oferece validação integrada e fácil de implementar, incluindo:- Validação em tempo real
- Validação personalizada
- Integração com bibliotecas como Yup, Zod ou Joi
 
- 
Melhor experiência de desenvolvimento- Fornece:- Tipagem forte com TypeScript
- DevTools para debugar
- Tratamento de erros intuitivo
 
- 
Gerenciamento de estados do formulário- Gerencia automaticamente estados como:- touched/untouched
- dirty/pristine
- validação
- submissão
 
Para fazer a instalação execute o comando em seu terminal:
$ npm i react-hook-form
commit: build: ➕ add react-hook-form lib $ npm i react-hook-form
  
  
  3 - Usando React Hook Form 
No arquivo src/pages/Home/index.tsx vamos importar a função useForm:
import { useForm } from 'react-hook-form'
useForm é um hook. Por convenção, um hook começa com use no nome. Os hooks são funções que acoplam uma funcionalidade em um componente existente.
useForm() retorna um objeto, então conseguimos fazemos a desestruturação desse objeto, e as funções principais são register e handleSubmit:
export function Home() {
  const { register, handleSubmit } = useForm()
}
register é uma função que vai adicionar um input ao nosso formulário. useForm() é como se a gente tivesse criado um novo formulário para a aplicação. E a função register diz quais os campos que vamos ter no nosso formulário.
Para registrar o TaskInput:
<TaskInput
 id="task"
 list="task-suggestions"
 placeholder="Dê um nome para o seu projeto"
 {...register("task")}
/>
A função register recebe o nome do input como argumento/valor e retorna vários métodos/funções e propriedades usadas no HTML:
Então com o spread operator {...register("task")} estamos pegando todos os métodos e as propriedades do register e passando para o componente TaskInput.
E o mesmo para o MinutesAmountInput:
<MinutesAmountInput
  type="number"
  id="minutesAmount"
  placeholder="00"
  step={5}
  min={5}
  max={60}
  {...register("minutesAmount", { valueAsNumber: true })}
/>
{ valueAsNumber: true } é para transformar de string para number.
  
  
  Usando handleSubmit
Habilitando o botão (usando o watch)
Com a função watch podemos observar o campo e saber em tempo real o valor dele: 
Usando variáveis auxiliares
Variáveis auxiliares são variáveis que não alteram a funcionalidade do código, mas melhoram a legibilidade do código.
O commit desta parte infelizmente eu acabei deixando junto com a parte 5 e a parte 6 😕 recomendo fazer a separação 😅
commit: feat: ✨ add controlled form with react-hook-form and validation with zod
  
  
  4 - Validação com Zod 
Por padrão, a biblioteca React Hook Form não traz nenhuma funcionalidade de validação. Ela prefere ser uma biblioteca enxuta, com menos funcionalidades, assim o usuário consegue escolher bibliotecas complementares de sua preferência, como, por exemplo, bibliotecas de validação de formulários baseada em esquema, já que existem ótimas opções como: Yup, Zod, Superstruct e Joi.
Aqui vamos utilizar a Zod, pois traz mais integração com TypeScript:
$ npm i zod
commit: build: ➕ add validation lib $ npm i zod
E para o React Hook Form fazer a integração com essas bibliotecas de validação, precisamos instalar o pacote @hookform/resolvers:
$ npm i @hookform/resolvers
commit: build: ➕ add lib to integrate react-hook-form with other libs $ npm i @hookform/resolvers
5 - Validação com o botão habilitado
Podemos ver na imagem abaixo que o botão fica desabilitado quando o campo está vazio:
Neste caso, não precisaríamos de validação, mas como em muitos formulários não acontecem isso e necessitam informar ao usuário qual informação está incorreta, vamos habilitar o botão e realizar a validação do formulário.
No arquivo src/pages/Home/index.tsx vamos fazer a importação do Zod:
import { zodResolver } from "@hookform/resolvers/zod";
import * as zod from "zod";
O código * as zod é uma técnica do ECMAScript Modules usado para importar tudo do pacote zod, já que ele não possui export default.
Antes de utilizar o zod, podemos ver no console.log(data) que adicionamos anteriormente neste mesmo arquivo, o formato do data como sendo um objeto:
No mesmo arquivo vamos realizar a validação então de um objeto com zod.object():
Vamos verificar a validação dos minutos com o Zod, mas para fazer isso, precisamos comentar o código HTML que já faz essa validação:
Agora podemos testar a validação do Zod. Quando clicamos no botão, percebemos que nenhum resultado aparece no console do navegador, ou seja, não está chegando no console.log pois estamos com erros de validação:
Visualizando os erros de validação do Zod
Para visualizar os erros de validação do Zod, temos que usar o formState. 
Perceba que o console.log(formState.errors) está fora da função handleCreateNewCycle:
Assim já conseguimos visualizar a mensagem de erro:
Caso eu queira colocar uma mensagem diferente:
Essas mensagens podem ser mostradas em tela para o usuário, mas nesse projeto, como temos a validação do campo númerico pelo HTML e o botão que só habilita quando há algo no campo de descrição, não iremos precisar mostrar essas mensagens ao usuário.
Assim podemos remover o formState e colocar o max={60} devolta.
O commit desta parte infelizmente eu acabei deixando junto com a parte 3 e parte 6 😕 recomendo fazer a separação 😅
commit: feat: ✨ add controlled form with react-hook-form and validation with zod
6 - TypeScript no Formulário
Agora vamos colocar uma tipagem para o data: any como mostrado na imagem abaixo:
Podemos já deduzir qual será a tipagem olhando para o nosso formulário, um objeto; com esses dois campos:
Podemos criar a tipagem de forma manual com interface:
Existe uma propriedade chamada de defaultValues que podemos passar pra o objeto de configuração dentro do useForm, que nos permite setar valores iniciais para os campos:
Se tentarmos usar o comando de autocomplete Ctrl + Space, não há sugestões válidas:
Para obtermos o autocomplete precisamos usar um generic, como mostrado quando paramos o mouse em cima do useForm, assim visualizamos os valores padrão <{}, any>:
Adicionando o generic obtemos o autocomplete:
Tipagem automática por inferência
Olhando para o código abaixo jé podemos perceber os tipos pela estrutura:
Usando infer do TypeScript conseguimos extrair a tipagem do zod.object() e, assim, podemos remover o interface:
Note que usamos a palara type, podemos assumir interface quando criamos o tipo manualmente, e type quando o tipo vem de forma automática.
Qual o benefício de usar o infer?
Se no futuro precisássemos adicionar um campo novo, por exemplo, chamado de owner, automaticamente o infer adicionaria o tipo do campo. Parando o mouse em cima de NewCycleFormData podemos notar o campo novo adicionado automaticamente:
Isso é o diferencial do Zod e você pode conferir tudo isso na documentação oficial da bilioteca.
O commit da parte 6 infelizmente eu acabei deixando junto com a parte 3 e parte 5 😕 recomendo fazer a separação 😅
feat: ✨ add controlled form with react-hook-form and validation with zod
7 - Resetando o Formulário
Ao iniciar o timer clicando no botão Começar, os campos não estão sendo resetados para o valor original. A biblioteca React Hook Form fornece a função reset para resetar os campos para os valores originais do defaultValues:
 
 
              






























 
    
Top comments (0)