Gerenciando formulários no React Native
Se você já construiu algumas telas com campos de texto ou informações preenchidas pelo usuário sabe como é verboso salvar os campos no estado do componente e não ter um encapsulamento de formulário assim como tempos no HTML em que todos inputs são facilmente recuperados com pouco código.
Provavelmente seu primeiro TextInput no React Native gerou um código muito parecido com esse:
<TextInput
onChangeText=(text => this.setState({ name: text }));
/>
Agora imagine uma tela com 40 TextInput’s, quanto código seria gerado? Quantos setState
teríamos em uma única tela? Isso porque no React você não controla a DOM através de classes ou ID’s e toda atualização de componente deve partir diretamente da view (sem eventListeners criados fora do render). Além disso, imagine adicionar validação em todos campos. Validação de e-mail? Apenas números? O problema fica cada vez maior.
TComb Form Native
A primeira lib que resolvi olhar foi o TComb Form Native, o grande barato dessa lib é poder escrever um único componente no render
e gerar o form inteiro a partir de um objeto que define os tipos dos campos.
Apesar de muito prática essa ferramenta possui limitações quando se trata do React Native, principalmente quando seus inputs são personalizados e se comportam de uma maneira diferente do padrão.
Recomendo usar essa biblioteca se seus forms forem muito simples e você precise de praticidade.
Redux-form
A mais famosa lib de formulários do ecossistema React. Apesar da lib realizar grande parte do gerenciamento do estado dos inputs do form e permitir customizar os campos e trabalhar de uma forma menos verbosa, eu (e muitas outras pessoas) não sou um grande fã de manter o estado dos campos do formulário do lado do Redux.
Formik
Depois de procurar em diversas libs, alguns usuários do Comunidade da RocketSeat me lembraram do Formik e resolvi experimentar novamente essa biblioteca.
Algo que nós devs sempre buscamos é tentar escrever a menor quantidade de código pra gerar a maior quantidade de funcionalidades, mas nem sempre isso é saudável, ou quase nunca.
A grande diferença do Formik para as outras bibliotecas de formulários é que ele não tenta fazer mágica, ao invés disso, essa lib encapsula nosso formulário oferecendo maneiras mais simples de tratarmos as validações, submits, valores padrão, erros, etc.
Para começar, podemos instalar o Formik com o comando:
yarn add formik
// Ou npm install --save formik
import React from 'react';
import { View, TextInput, Button } from 'react-native';
import { withFormik } from 'formik';
const Form = (props) => (
<View style={styles.container}>
<TextInput
value={props.values.email}
onChangeText={text => props.setFieldValue('email', text)}
/>
<TextInput
value={props.values.password}
onChangeText={text => props.setFieldValue('password', text)}
/>
<Button
onPress={props.handleSubmit}
title="Login"
/>
</View>
);
export default withFormik({
mapPropsToValues: () => ({ email: '', password: '' }),
handleSubmit: (values) => {
console.log(values);
}
})(Form);
Escrevemos nosso formulário da mesma forma que escreveríamos sem utilizar a biblioteca, porém no lugar do setState
no método onChangeText
utilizamos a função setFieldValue
que é embutida nas propriedades do componente através da composição realizada no final do arquivo com o withFormik
.
Da mesma forma, temos um método handleSubmit
que podemos chamar através do onPress
do botão para realizar o envio do form.
Perceba que utilizo a função withFormik
para compor meu componente Form
da mesma forma que utilizamos no connect
do Redux e como parâmetro passo um objeto com duas propriedades:
mapPropsToValues
: uma função que recebe nosso estado inicial dos inputs, pode receber asprops
do componente como parâmetro para customizar os valores.handleSubmit
: executada no submit do formulário, responsável por realizar a tratativa dos dados e retornar os erros de API (não de validação) caso necessário. A variável values é um objeto com cada campo e seu valor, por exemplo:{email: 'diego@exemplo.com', password: 123456}
.
Até agora não existe muita vantagem, certo? Vamos ver do que o Formik é capaz.
Loading
O Formik oferece uma propriedade isSubmitting
que contém a informação de loading do handleSubmit, assim conseguimos exibir uma informação de carregamento no componente:
{ props.isSubmitting && <ActivityIndicator /> }
Erros
Pense que precisemos exibir uma mensagem de erro (não erro de validação) caso a requisição à API tenha falhado, com o Formik fica muito fácil:
handleSubmit: (values, { setSubmitting, setErrors }) => {
apiService.post('/authenticate', values)
.then(/* sucesso */)
.catch(err => {
setSubmitting(false);
setErrors({ message: err.message });
});
}
Utilizamos o método setSubmitting
para indicar que não estamos mais realizando o loading e o método setErrors
para preencher a propriedade de erros. Com isso, agora podemos exibir o erro em tela com a propriedade errors
:
{ props.errors.message && <Text>{props.errors.message}</Text> }
asassad
Validação
A validação dos campos é um dos maiores pontos positivos do Formik. Para obter o máximo da validação, vamos utilizar um pacote chamando Yup que nos ajudará na hora de definir as regras de cada campo, para instalá-lo basta utilizar o comando:
yarn add yup // Utilize NPM se preferir
E importá-lo utilizando:
import Yup from 'yup';
A validação é adicionada no objeto passado como parâmetro da função withFormik
, vamos ver como funciona um exemplo de validação de e-mail e senha simples:
export default withFormik({
mapPropsToValues: () => ({ email: '', password: '' }),
validationSchema: Yup.object().shape({
email: Yup.string()
.email('Digite um e-mail válido')
.required('Preencha o campo de e-mail'),
password: Yup.string()
.min(6, 'A senha deve ter no mínimo 6 caracteres')
.required('Preencha o campo de senha'),
}),
handleSubmit: (values) => {
...
}
})(App);
Sempre começamos com o método .object
e .shape
para indicar nossas validações e seguimos com os nomes dos campos nas propriedades e as validações logo após. Você pode encontrar uma lista de todas validações possível nesse link.
Agora, quando realizamos o submit e uma das validações falhar, podemos acessá-las também com o objeto errors
:
{ props.errors.email && <Text>{props.errors.email}</Text> }
Por padrão as validações são feitas enquanto o usuário digita, você pode desabilitar essa opção repassando o validateOnChange: false
para o objeto parâmetro do withFormik
. Se quiser manter esse tipo de validação porém não exibir o erro na primeira digitação do usuário, basta unir a propriedade touched
enviada ao componente com a propriedade errors
para validar se um campo já foi preenchido pelo menos uma vez:
{ props.touched.email
&& props.errors.email
&& <Text>{props.errors.email}</Text> }
Concluindo
Apesar de ter passado pelas principais funcionalidades do Formik nesse post, a biblioteca ainda possui muitas opções de configuração, validações customizadas, etc, recomendo muito ir mais a fundo nisso de acordo com que sua aplicação necessite por serem opções mais avançadas.
Se você gostou desse post não esquece de deixar um comentário e suas ?