Índice:

Criação de formulários utilizando o Formik

Índice:

Neste artigo, vou te mostrar como é possível otimizar o desenvolvimento de formulários através da utilização do Formik. Confira abaixo!

Introdução

Raros são os sistemas que não possuem qualquer tipo de formulários. Login, cadastros, edições, pesquisas e wizards são alguns dos exemplos de forms que estão presentes na grande maioria dos aplicativos e sites.

A primeiro momento, gerenciar esses forms parece ser uma tarefa simples: o usuário preenche os campos e, posteriormente, os dados são enviados para algum lugar. Entretanto, as coisas podem ficar mais complexas devido às peculiaridades ou até mesmo o tamanho do sistema e por isso é necessário encontrar uma forma de padronizar esse processo de criação dos formulários.

Praticamente todos os formulários devem ter validações client-side para melhorar a experiência do usuário. Afinal, ninguém quer preencher um formulário gigantesco sem saber se está digitando as informações como o esperado ou não.

Além disso, é comum que os mesmos formulários apareçam em diversas partes da aplicação, mesmo que de formas distintas, ora inserindo dados, ora editando aqueles previamente já inseridos, por exemplo. Todavia, implementar validações e re-usabilidade do código não é uma tarefa tão simples.

Formik

Pensando nesses problemas tão comuns na hora de criar formulários, Jared Palmer e Ian White decidiram criar uma biblioteca que facilitasse o gerenciamento de estados dos forms no React (ou React Native), trabalhando com o estado local do componente ao contrário de outras libs que trabalham com o estado global, que acabam adicionando muitas camadas de complexidade e perdendo desempenho.

Além disso, o Formik foi criado para ser simples e organizado, todo o processo de criação de forms com ele é muito rápido e envolve pouca linhas código para se ter um formulário reutilizável e com validação (esse último ponto temos que agradecer também ao Yup, que veremos daqui a pouco).

Vamos lá?!

Criaremos uma aplicação bem simples para demonstrar algumas das diversas features dentro do Formik. Toda estilização fica por sua conta, assim conseguimos focar no mais importante deste artigo.

Estou usando o React Native, mas lembre-se que o Yup foi desenvolvido para a biblioteca React e, portanto, não está intrinsecamente ligado ao framework RN. Isso permite que ele seja utilizado tanto para aplicações Web quanto Mobile.

Antes de qualquer coisa vamos instalar as duas dependências necessárias:

yarn add formik yup

Vamos construir algo que se pareça com isso, já utilizando a estrutura do Formik:

Página mobile onde está sendo feita uma demonstração da estrutura inicial do Formik.
Figura 1 – Estrutura inicial

Para montar a estrutura de um formulário vamos utilizá-los com HOCs (High Order Components).

No exemplo acima, o form não foi escrito dentro da tela que está sendo exibida. Neste caso, o mesmo foi criado em outro arquivo para que outras telas possam reutilizá-lo.

Iremos interagir com o formulário (receber os dados, limpar os campos, definir os valores iniciais, etc…) dentro do HOC, enviando os props necessários.

Exemplo de estrutura do formulário
Figura 2 – Exemplo de estrutura

Portanto, nosso arquivo src/Example/index.js, que é a estrutura do formulário ficou dessa forma:

import React from 'react';
import {View, StyleSheet, TouchableOpacity, Text} from 'react-native';
import {Formik} from 'formik';
import TextInput from '../../components/TextInput';

function ExampleForm({onSubmit, initialValues, style}) {
  const renderForm = ({
    values,
    setFieldValue,
    setFieldTouched,
    touched,
    errors,
    handleSubmit,
    isValid,
    isSubmitting,
  }) => {
    return (
      <View style={StyleSheet.flatten([styles.container, style])}>
        <TextInput
          onChange={setFieldValue}
          onTouch={setFieldTouched}
          placeholder="Nome"
          name="name"
          value={values.name}
          error={touched.name && errors.name}
        />
        <TextInput
          onChange={setFieldValue}
          onTouch={setFieldTouched}
          keyboardType="email-address"
          autoCapitalize="none"
          placeholder="E-mail"
          name="email"
          value={values.email}
          error={touched.email && errors.email}
        />
        <TextInput
          onChange={setFieldValue}
          onTouch={setFieldTouched}
          placeholder="Senha"
          name="password"
          secureTextEntry={true}
          value={values.senha}
          error={touched.password && errors.password}
        />
        <TextInput
          onChange={setFieldValue}
          onTouch={setFieldTouched}
          placeholder="Confirmar senha"
          name="passwordConfirm"
          secureTextEntry={true}
          value={values.passwordConfirm}
          error={touched.passwordConfirm && errors.passwordConfirm}
        />
        <TouchableOpacity
          disabled={!isValid || isSubmitting}
          onPress={handleSubmit}
          style={StyleSheet.flatten([
            styles.submit,
            !isValid ? styles.submitDisabled : null,
          ])}>
          <Text style={styles.submitText}>Enviar</Text>
        </TouchableOpacity>
      </View>
    );
  };

  return (
    <Formik
      initialValues={initialValues}
      onSubmit={onSubmit}
      render={renderForm}
    />
  );
}

ExampleForm.defaultProps = {
  initialValues: {},
  onSubmit: () => null,
};

const styles = StyleSheet.create({
  container: {},
  submit: {
    height: 50,
    backgroundColor: '#f2b50c',
    justifyContent: 'center',
    alignItems: 'center',
    marginHorizontal: 6,
  },
  submitText: {
    fontSize: 16,
    fontWeight: 'bold',
  },
  submitDisabled: {
    backgroundColor: '#d1cfcf',
  },
});

export default ExampleForm;

Aqui temos um componente funcional que retorna o componente disponibilizado pelo Formik passando algumas props. Vamos dar uma olhada nessas props:

  • initialValues: Essa prop deve ser um objeto que contenha os valores iniciais dos campos no formulário (podemos deixar null se não temos nenhum). Recebemos os valores iniciais (se existirem) do HOC.
  • onSubmit: Aqui passamos o callback do HOC para que quando o usuário envie os valores do form eles sejam passados para o componente acima.
  • render: Responsável por receber o componente do form e o renderizar. Além disso, render envia diversas props para o componente a ser renderizados. Iremos utilizar essas propriedades para construir o formulário na função  renderForm, seguindo os padrões do Formik.

Dentro da função renderForm iremos desestruturar diversas funções e objetos (existem muitos outros, o recomendado é olhar na documentação oficial para saber quais outros existem e a funcionalidade de cada um).

Para os Fields (como o Formik os chama), precisamos enviar as props que possibilitam que o componente atualize os estados do form.

Nesse caso, estamos utilizando um componente customizado, o TextInput, que veremos como foi estruturado logo abaixo, e precisamos passar o name, que deve ser único entre os campos, o value que contem o valor atual do field e as funções para setar o valor e blue do input.

src/components/TextInput.js

import React from 'react';
import {View, Text, StyleSheet, TextInput as RNTextInput} from 'react-native';

function TextInput({
  style,
  inputStyle,
  error,
  errorStyle,
  onChange,
  onTouch,
  name,
  ...attributes
}) {
  const onChangeText = text => {
    onChange(name, text);
  };

  const onBlurText = () => {
    onTouch(name);
  };

  return (
    <View style={StyleSheet.flatten([styles.container, style])}>
      <View style={styles.inputContainer}>
        <RNTextInput
          style={StyleSheet.flatten([styles.inputStyle, inputStyle])}
          onChangeText={onChangeText}
          onBlur={onBlurText}
          underlineColorAndroid="transparent"
          {...attributes}
        />
      </View>
      {error ? (
        <Text style={StyleSheet.flatten([styles.error, errorStyle])}>
          {error}
        </Text>
      ) : null}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    paddingVertical: 10,
    paddingHorizontal: 6,
  },
  inputContainer: {
    justifyContent: 'center',
    borderWidth: 1,
    borderColor: 'black',
    paddingHorizontal: 10,
  },
  inputStyle: {
    fontSize: 16,
    height: 50,
  },
  error: {
    marginTop: 8,
    color: 'red',
    fontSize: 15,
  },
});

export default TextInput;

Vale ressaltar que qualquer componente customizado pode ser integrado ao Formik, seja ele um checkbox, radio-button, entre outros. Basta integrá-lo com os parâmetros citados acima.

Como estamos no RN, essa integração dos componentes é um pouco diferente do convencional da Web, caso queira ver as diferenças vale a pena dar uma olhada na documentação oficial.

A implementação do form no arquivo App.js ficou assim:

import React, {useCallback, useState} from 'react';
import {SafeAreaView, StyleSheet, Text} from 'react-native';

import ExampleForm from './src/forms/Example';

const App = () => {
  const [formData, setFormData] = useState(JSON.stringify('{}'));

  const onSubmit = useCallback(async (values, bag) => {
    try {
      setFormData(JSON.stringify(values, null, 2));
    } catch (e) {
      bag.setErrors(e);
    } finally {
      bag.setSubmitting(false);
    }
  }, []);

  return (
    <SafeAreaView style={styles.safeArea}>
      <ExampleForm onSubmit={onSubmit} />
      <Text style={styles.values}>{formData}</Text>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  safeArea: {
    flex: 1,
  },
  values: {
    fontSize: 16,
    marginHorizontal: 6,
    marginTop: 15,
    marginBottom: 40,
  },
});

export default App;

Validando o formulário com Formik

Outra parte fundamental de qualquer formulário é a possibilidade de validar os campos antes que o usuário os envie para uma API, por exemplo. Essa implementação fornece uma melhor experiência para o usuário, já que ele não terá que aguardar a resposta do servidor para validar algo que o próprio client teria capacidade.

Entretanto, é importante ter em mente que a validação client-side é considerada insegura e serve somente o propósito de facilitar o processo para o usuário final. A validação server-side ainda é fundamental.

Vamos criar o arquivo de validação para nosso formulário Exemplo. Dentro do arquivo validation.js, iremos utilizar o Yup, uma biblioteca que simplifica infinitamente o processo de criação de regras dos campos.

import * as Yup from 'yup';

export default Yup.object().shape({
  name: Yup.string()
    .min(4, 'Mínimo 4 caracteres')
    .max(20, 'Máximo 20 caracteres'),
  email: Yup.string()
    .email('E-mail inválido')
    .required('E-mail obrigatório'),
  password: Yup.string()
    .min(4, 'Mínimo 4 caracteres')
    .required('Obrigatório'),
  passwordConfirm: Yup.string()
    .min(4, 'Mínimo 4 caracteres')
    .oneOf([Yup.ref('password'), null], 'As senhas não correspondem')
    .required('Obrigatório'),
});

Agora, importe o objeto criado pelo Yup no componente do formulário e passe-o como prop no component do Formik.

import validation from './validation';
<Formik
  initialValues={initialValues}
  onSubmit={onSubmit}
  render={renderForm}
  validationSchema={validation}
/>

Pronto! Nosso formulário somente estará disponível para ser enviado quando todos os requerimentos definidos no objeto de validação forem satisfeitos.

Finalizando

Apesar de simples, nosso formulário funciona brilhantemente. Agora que você já implementou funcionalidades básicas de qualquer formulário, vale a pena explorar outras possibilidades de validação com o Yup e outras funcionalidades do Formik.

Figura 3 – Estrutura final

Qualquer dúvida ou sugestão deixe nos comentários aí embaixo, vamos sempre estar de olho! Para conferir outros assuntos no nosso blog, basta clicar aqui. Obrigado pela leitura!

 

Publicado por:
Compartilhe:

Posts relacionados

métrica developer experience

Entender e otimizar a developer experience é crucial para o sucesso de qualquer projeto de software. Uma experiência positiva pode impulsionar a produtividade e a satisfação da equipe, elementos chave

developer experience

A developer experience, ou DX, é um conceito cada vez mais importante no cenário de desenvolvimento de software. Mas por que a experiência do desenvolvedor é tão importante? Como ela

estimativa de software

Estimar software vai muito além de apenas chutar prazos. É sobre sincronizar de forma inteligente os esforços de desenvolvimento, garantindo que cada recurso seja usado onde realmente importa. Pensando nisso,