Como construir formulários usando React Hook Form e Yup com ChakraUI
Published: 2022-12-22 20:43:30

Em HTML, é o comportamento padrão dos formulários redirecionar para uma nova página sempre que são enviados. Portanto, para fornecer funcionalidade dinâmica, o React usa uma estratégia chamada **componentes controlados**.

Se você fez recentemente um curso de React, provavelmente não gostou desta parte, porque há muitos estados para gerenciar se você tiver vários inputs.

Primeiramente, você rastreia o estado do input usando a propriedade **onChange** que chama a função **useState()**. Os inputs são agrupados em torno de um elemento de formulário.

Quando o usuário envia o formulário, ele aciona a propriedade **onClick** ou **onSubmit** para definir as entradas para uma array contendo valores ou objetos, dependendo do número de inputs.

Em seguida, vem a validação, que verifica se o usuário inseriu alguma entrada. Caso contrário, retorne um erro, solicitando que o usuário insira uma entrada válida.

A lógica aqui é um monte de clichê. Você pode ficar entediado só de ouvir sobre o processo.

E se eu te disser que uma única biblioteca pode conseguir tudo isso?

**1.** O que é React-Hook-Form?

**2.** Como o React-Hook-Form afeta o desempenho 

**3.** Como obter dados do usuário de um formulário

**4.** Como adicionar validação aos seus formulários com Yup

**5.** Como obter dados do usuário em um formulário que utiliza bibliotecas externas


## O que é React-Hook-Form?

React Hook Form é uma biblioteca flexível que cuida de toda a sua validação, gerenciamento de estado e dados do usuário - e está tudo compactado em um tamanho de apenas 25,3kb (descompactado) e 9,1kb GZip (alterações com versões).

É simples e direto de usar, e você precisa escrever um código mínimo.


![Imagem com o tamanho do React-Hook-Form](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9yvn9yzo1pxyjdnj2p0g.png)

Uma das características que me impressiona, é o seu desempenho. Conforme mencionado em seu [Site oficial](https://react-hook-form.com/), React-Hook-Form:

> _Minimiza o número de re-renderizações e montagem mais rápida, esforçando-se para fornecer a melhor experiência do usuário._

## Como o React-Hook-Form afeta o desempenho

Se você estiver utilizando as versões anteriores da biblioteca, a documentação geralmente faz referência á propriedade **ref** para manipular o gerenciamento e a validação do estado.

```jsx
<input type=”password” placeholder=”Password” ref={register} />
```
Dessa forma, o React-Hook-Form adota um método de entrada **descontrolada**, em vez de alterar o estado todas as vezes. Ele isola o componente selecionado e evita a renderização dos componentes filhos.

Isso reduz significamente o número de novas renderizações e aumenta o desempenho geral da aplicação.

## Como obter dados do usuário de um formulário

E aqui está o que estaremos construindo. É um formulário simples com validação.

Eu criei um Codesandbox para este tutorial específico, portanto, certifique-se de consultá-lo caso se perca.

Aqui está o que você precisa acompanhar:

[Link da aplicação](https://3wfv3f.csb.app/)

[Código fonte](https://codesandbox.io/s/immutable-dust-3wfv3f?file=/src/App.tsx)

![Imagem do formulário](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4qhx7gmjarvuqwc035td.png)

Primeiro, vamos instalar as dependências:

Com npm:

```
npm i react-hook-form @chakra-ui/react @emotion/react @emotion/styled @hookform/resolvers yup
```
Com yarn:

```
yarn add react-hook-form @chakra-ui/react @emotion/react @emotion/styled @hookform/resolvers yup
```

Primeiro vamos fazer as importações:

```jsx
import * as yup from "yup";
import { yupResolver } from "@hookform/resolvers/yup";

import { useForm } from "react-hook-form";
```

Crie as tipagens dos dados que serão enviados nos inputs:


```jsx
type Form = {
  name: string;
  lastName: string;
  sex: string;
};
```


Desestruture as seguintes constantes do hook useForm e atribua o schema com as validações ao resolver do **useForm**:


```jsx
const { register, formState, control, handleSubmit } = useForm();
```


Desestruture as constantes **errors** e **isSubmitting** de formState:



```jsx
const { errors, isSubmitting } = formState;
```


Usaremos a constante **errors** para acessar a mensagem de erro retornada do schema de validações. Por último, usaremos o **isSubmitting** na propriedade isLoading do botão do Chakra, para aparecer um spinner de carregamento enquanto o formulário está sendo enviado.

Crie um formulário simples como este:

```jsx
<Flex as="form" onSubmit={handleSubmit(handleSend)}>
  <FormControl isInvalid={!!errors}>
  <Stack>
    <Input
      type="text"
      name="name"
      placeholder="Nome"
      ref={yup.ref}
      {...register("name")}
    />

    {!!errors && 
    <FormErrorMessage>
        {errors?.name?.message}
    </FormErrorMessage>}

    <Input
      type="text"
      name="lastname"
      ref={yup.ref}
      placeholder="Sobrenome"
      {...register("lastname")}
    />

    {!!errors && (
      <FormErrorMessage>
          {errors?.lastname?.message}
      </FormErrorMessage>
    )}

    <Controller
      control={control}
      name="sex"
      rules={{ required: true }}
      render={({ field }) => (
        <Stack>
          <Text size="md" fontWeight={500}>
            Sexo
          </Text>

          <RadioGroup color="gray.400" {...field}>
            <Stack spacing={5} direction="row">
              <Radio
                colorScheme="blue"
                value="Masculino"
                isInvalid={errors.sex?.type === "required"}
              >
                Masculino
              </Radio>

              <Radio
                colorScheme="blue"
                value="Feminino"
                isInvalid={errors.sex?.type === "required"}
              >
                Feminino
              </Radio>
            </Stack>
          </RadioGroup>

          {!!errors && (
            <FormErrorMessage>
                 {errors?.sex?.message} 
            </FormErrorMessage>
          )}
        </Stack>
      )}
    />

    <Button type="submit" isLoading={isSubmitting}>
      Enviar
    </Button>
  </Stack>
  </FormControl>
</Flex>
```

Usamos a função **register** para fazer com que o valor seja validado e enviado no formulário:

```jsx
<Input type="text" name="name" {...register("name")} />
```

Para enviar os dados, criamos a função **handleSend**. Para que ela funcione usando Typescript, você precisará usar a tipagem SubmitHandler do próprio React-Hook-Form, passando a tipagem dos dados do seu formulário:

```jsx
const handleSend: SubmitHandler<Form> = async (values) => {
    await new Promise((resolve) => setTimeout(resolve, 2000));
    console.log({ submited: values });
  };
```

Então passamos a função **handleSend** como parâmetro da função **handleSubmit** do próprio React-Hook-Form, para que os dados sejam enviados:

```jsx
<Flex as="form" onSubmit={handleSubmit(handleSend)}>
   {...}
</Flex>
```

## Como adicionar validação aos seus formulários com Yup

Fazer validações nunca foi tão simples com o **Yup**, você pode fazer validações simples e complexas de forma extremamente expressiva. 

Crie o schema com as validações:

```jsx
const createFormSchema = yup.object({
    name: yup.string().required("Você deve digitar seu nome"),
    lastname: yup.string().required("Você deve digitar seu sobrenome"),
    sex: yup.string().required("Insira o seu sexo")
  });
```

Agora atribua o schema de validações no resolver do **useForm**:



```jsx
const { register, formState, control, handleSubmit } = useForm({
    mode: "onChange",
    resolver: yupResolver(createFormSchema)
  });
```



Usamos a constante **errors** para validar que caso exista alguma mensagem de validação, ela seja renderizada no componente **FormErrorMessage** do Chakra, veja o exemplo:



```jsx
{!!errors && 
    <FormErrorMessage>
        {errors?.name?.message}
    </FormErrorMessage>}
```

## Como obter dados do usuário em um formulário que utiliza bibliotecas externas

Se você analisar o código acima, perceberá que usamos a função **register** para fazer com que o valor seja validado e enviado no formulário. Então por qual motivo não estamos utilizando-o para registrar e validar o valor dos Radios?

O React-Hook-Form foi construído para ser usado com um HTML tradicional, sem uma biblioteca externa como o **ChakraUI** ou qualquer outra biblioteca semelhante. Estamos usando inputs do tipo radio personalizados do Chakra, portanto o React-Hook-Form não conseguirá registrar o valor dessa forma.

Para solucionar este problema, o Chakra fornece o componente **Controller**, no qual podemos usá-lo para registrar e validar os valores de componentes que usamos de bibliotecas externas.

## Obrigado por ler! ✨
É bom ver que você leu até aqui. Se você obteve algumas informações com este artigo, sinta-se à vontade para compartilhá-lo com sua comunidade e colegas de trabalho.

Eu falo sobre tecnologias da web e projetos de construção,
documentando ainda mais o processo de desenvolvimento para outros desenvolvedores fazerem referência. Se precisar de alguma orientação, não deixe de comentar aqui.