Criando formulários em React Native utilizando React Hook Form e Yup
--
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
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:
É isto 💜.