Criando formulários em React Native utilizando React Hook Form e Yup

Gabriel Menezes
6 min readJun 12, 2020

--

Photo by Caspar Camille Rubin on Unsplash

Criar formulários em React Native costuma ser trabalhoso. É necessário lidar com as entradas do usuário, validação de texto, cenários de erro e boa performace. Neste artigo irei explicar detalhadamente como criar um formulário básico, de forma mais simples e sem dor de cabeça com o React Hook Form.

Histórico

As alternativas utilizadas pela Popcode para a criação de formulários nesses últimos anos pareciam atender nossas necessidades, mas com o tempo isso foi deixando de ser verdade.

Primeiramente utilizamos o Redux-Form, na época era uma alternativa para o TextInput do próprio React Native, ele contornava muito bem alguns problemas, e automaticamente salvava os dados no Redux, parecia muito bom. O problema era que ele re-renderizava todo o estado da aplicação ao mudar qualquer letra em um campo de texto.

Algum tempo depois optamos por utilizar o Formik que também parecia uma boa opção, já que era possível validar os dados utilizando o Yup, mas ainda assim o Formik também tinha seus problemas com re-renderizações, inclusive foi discutido nesta thread, onde o próprio criador da biblioteca participou. No fim, alguns usuários resolveram mudar de biblioteca por conta dos problemas de renderização.

Estes são exemplos de código que estão na documentação do Redux-Form e Formik

Exemplo Redux-Form

Exemplo Formik

Ambas as implementações consomem muitas linhas de código, dificultando a manutenção e o entendimento dos desenvolvedores que abrem as telas com campos de texto que utilizam essas bibliotecas.

Por fim, resolvemos utilizar uma biblioteca que é bem utilizada no React Web e que agora tem suporte para React Native, a React Hook Form.

React Hook Form

A biblioteca traz a proposta de criar formulários flexíveis, com formas simples de fazer validação e sem renderizações desnecessárias. Na própria documentação existe comparativo feito entre Redux-Form x Formik x React Hook Form. É interessante ver a diferença no tamanho, legibilidade do código e número de renderizações de formulários idênticos.

Implementação

Vamos criar um formulário bem simples, utilizando apenas dois campos (e-mail e senha), mas a ideia segue a mesma para formulários maiores.

O básico

Para começar, podemos implementar um Campo de Texto com label, que é o que geralmente utilizamos nos aplicativos da Popcode. Podemos manter as mesmas propriedades que o TextInput normal recebe, para que tenhamos a liberdade de alterar o que for necessário.

const TextField = ({ label, ...inputProps }) => (
<View style={styles.container}>
<Text style={styles.label}>{label}</Text>
<TextInput
style={styles.input}
{...inputProps}
/>
</View>
)

Vamos também criar uma tela contendo os dois campos de texto com label e placeholder, além do botão para validar os dados digitados nos campos de texto.

const LoginScreen = () => {
return (
<View style={styles.mainContainer}>
<TextField
label={'Email'}
placeholder={'Digite seu email'}
/>
<TextField
label={'Senha'}
placeholder={'Digite sua senha'}
/>
<Button onPress={() => {}} text={'Continuar'} />
</View>
)
}

Adicionando o React Hook Form

Com a implementação do código acima, não temos nenhum controle sobre o que é digitado nos campos de texto e também não temos validação, nem podemos utilizar os dados, mas agora é que a mágica acontece.

import { useForm } from 'react-hook-form'...

O React Hook Form nos dá um Hook para facilitar toda a implementação de como lidar com os formulários. Vamos utilizá-lo dessa forma:

...const { register, setValue, handleSubmit } = useForm()....

A biblioteca nas três funções para ajudar a lidar com os dados dos campos de texto são:

  • Register → Registra os campos com uma key para cada campo de texto;
  • SetValue → Armazena o que está sendo digitado no campo de texto;
  • HandleSubmit → É uma função que trata a submissão dos dados digitados nos campos de texto.

Para registrar os campos de formulários que serão utilizados, adicionamos um useEffect que irá executar assim que a tela for criada. Dentro dele colocaremos a função register com uma chave para campo de texto, neste caso iremos criar para e-mail e senha.

...useEffect(() => {
register('email')
register('password')
}, [register])
...

Após o registro, já é possível utilizar a propriedade onChangeText do próprio React Native junto com a função de setValue. Utilizaremos em cada um dos campos de texto, passando como parâmetros a chave do campo e o texto que está sendo digitado.

...<TextField
label={'Email'}
placeholder={'Digite seu email'}
onChangeText={text => setValue('email', text)}
/>
<TextField
label={'Senha'}
placeholder={'Digite sua senha'}
onChangeText={text => setValue('password', text)}
/>
...

A partir desse momento o texto digitado nos campos de texto já estão sendo salvos internamente pela biblioteca. Porém, ainda falta um pequeno detalhe: lidar com esses dados. Faremos isso utilizando o handleSubmit. Ela aceita como parâmetro uma função de callback que receberá os valores exibidos nos campos de texto.

Criamos uma função chamada onSubmit para exibir um alerta com os dados que ela receberá, apenas para exemplificar como utilizar os dados que a função handleSubmit passará para ela.

...const onSubmit = (data) => Alert.alert(data.email, data.password)... <Button onPress={handleSubmit(onSubmit)} text={'Continuar'} />...

Com poucos passos já temos um formulário funcional onde é possível registrar e manipular os dados para salvar no estado da aplicação ou até mesmo fazer uma requisição na API (alterando a função onSubmit). Porém, ainda precisamos validar os campos digitados e apresentar para o usuário o cenário de erro, se necessário.

Validação

Existem algumas formas de fazer a validação dos dados digitados no campo de texto, nesse caso iremos utilizar o Yup, que nos permite criar um Schema de validação para garantir que os dados estão de acordo com o que desejamos e tem total integração com o React Hook Form.

Recomendo fortemente dar uma olhada na documentação do Yup para entender melhor como funciona a validação dos dados.

Vamos criar um Schema para validar os campos digitados, utilizando as opções string() e required(), por exemplo. É possível também especificar a mensagem de erro que será retornada quando o campo não satisfizer a validação proposta.

Agora é necessário alterar o useForm adicionando o parâmetro validationSchema, assim o handleSubmit vai lidar com a validação dos dados.

...const fieldsValidationSchema = yup.object().shape({
email: yup
.string()
.required('O email não pode ser vazio')
.email('Digite um email válido'),
password: yup
.string()
.required('A senha não pode ser vazia')
.min(6, 'A senha deve conter pelo menos 6 dígitos')
})
...const { register, setValue, handleSubmit, errors } = useForm({ validationSchema: fieldsValidationSchema })

Dessa forma o handleSubmit não vai permitir que a função onSubmit seja executada quando os dados não passarem na validação do Yup. Quando isso acontece um erro é disparado no campo que estiver com problemas na validação sendo adicionado no objeto errors.

Tratamento de erros

Agora com a validação funcionando e utilizando o campo errors que o useForm fornece será necessário apenas exibir o erro para o usuário saber qual é o problema a ser resolvido.

Vamos passar o objeto contendo a mensagem de erro para cada componente FieldText e dentro do componente será feito tratamento do erro exibindo na tela.

// Tela Screen.jsconst { register, setValue, handleSubmit, errors } = useForm({ validationSchema: fieldsValidationSchema })...<TextField
label={'Email'}
error={errors?.email}
placeholder={'Digite seu email'}
onChangeText={text => setValue('email', text)}
/>
<TextField
label={'Senha'}
error={errors?.password}
placeholder={'Digite sua senha'}
onChangeText={text => setValue('password', text)}
/>
...// Componente TextField.js...<View style={styles.container}>
<Text style={styles.label}>{label}</Text>
<TextInput
style={[styles.input, !!error && styles.borderError]}
{...inputProps}
/>
{!!error && <Text style={styles.errorMessage}>{error.message}</Text>}
</View>
...

Conclusão

Diferente das outras bibliotecas que utilizamos no passado, a React Hook Form tem um código mais simples e intuitivo; facilitando a implementação, o entendimento e a manutenção dos desenvolvedores que mexerão nesse código no futuro.

Essa biblioteca fornece várias maneiras de manipular, validar e armazenar os dados e as mensagens de erro (está tudo bem documentado aqui). Os criadores também disponibilizaram um repositório com diversos exemplos de utilização da biblioteca. Vale a pena conferir também.

Deixo abaixo o arquivo completo da implementação desse formulário:

LoginScreen.js

LoginScreen.style.js

É isto 💜.

--

--