Controlando y validando formularios en Nextjs con Formik y Yup

Recently updated on marzo 21st, 2024 at 03:49 pm

Comencemos definiendo que son cada uno de ellos…

Formik


Formik es una biblioteca de gestión de formularios para React que facilita la tarea de manejar formularios complejos y manejar el estado de los datos del formulario de manera eficiente. Formik simplifica el proceso de validación, manejo de cambios y envío de datos del formulario, reduciendo la cantidad de código necesario para estas tareas comunes.

Algunas características clave de Formik incluyen:

  1. Gestión del Estado del Formulario: Formik maneja el estado del formulario de manera eficiente, incluyendo el seguimiento de los valores de los campos, su validación y su estado de "tocado" o "no tocado" (es decir, si el usuario ha interactuado con ellos o no).
  2. Validación de Formularios: Facilita la validación de formularios con un esquema de validación simple y flexible, permitiendo definir reglas de validación para cada campo del formulario.
  3. Manejo de Eventos y Cambios: Proporciona un conjunto de funciones y hooks para manejar eventos como cambios en los campos, envío del formulario, manejo de errores, entre otros.
  4. Integración con Componentes de React: Es compatible con la mayoría de los componentes de React, lo que facilita su integración en aplicaciones existentes.
  5. Soporte para Contexto y Hooks: Utiliza el contexto de React y los hooks para compartir la lógica del formulario de manera eficiente entre diferentes componentes de la aplicación.

En resumen, Formik simplifica el manejo de formularios en aplicaciones React al proporcionar una API intuitiva y eficiente para gestionar el estado, la validación y el envío de datos de los formularios. Es una herramienta popular entre los desarrolladores de React debido a su facilidad de uso y potentes funcionalidades.

Yup

Yup es una biblioteca de validación de esquemas para JavaScript y Node.js que se utiliza comúnmente en aplicaciones web y móviles para validar datos de entrada, como formularios o API endpoints. La principal característica de Yup es su capacidad para definir esquemas de validación de datos de forma sencilla y poderosa.

  1. Definición de Esquemas de Validación: Permite definir fácilmente esquemas de validación para diferentes tipos de datos, como cadenas, números, booleanos, objetos, arreglos, etc. Los esquemas se pueden personalizar con reglas específicas, como requerido, longitud mínima o máxima, formato de fecha, expresiones regulares, valores permitidos, entre otros.
  2. Encadenamiento de Validadores: Yup utiliza un sistema de encadenamiento de métodos para aplicar múltiples validadores a un campo de datos. Esto permite definir reglas de validación complejas de manera intuitiva y legible.
  3. Mensajes de Error Personalizados: Permite personalizar los mensajes de error para cada validador, lo que facilita la comunicación de errores de validación específicos al usuario.
  4. Validación Asincrónica: Yup admite la validación asincrónica, lo que significa que se pueden realizar validaciones que requieren interacciones asincrónicas, como la validación de un valor de campo a través de una llamada a una API.
  5. Integración con Bibliotecas de Gestión de Formularios: Se integra fácilmente con bibliotecas populares de gestión de formularios en JavaScript, como Formik (para React) o Redux-Form, para proporcionar una experiencia de validación de formularios completa y robusta.

En resumen, Yup es una biblioteca potente y flexible para la validación de esquemas en JavaScript y Node.js que facilita la definición y aplicación de reglas de validación en diferentes tipos de datos. Es ampliamente utilizada en el desarrollo de aplicaciones web y móviles para garantizar la integridad y precisión de los datos de entrada.

Validando un formulario

Lo primero que debemos hacer es añadir Formik y Yup a nuestro proyecto. Abre una terminal y ejecuta el siguiente comando:

yarn add formik yup

Para este tutorial, estaremos utilizando las siguientes dependencias:

{
  "dependencies": {
    // ...
    "formik": "^2.4.5",
    "next": "14.1.3",
    "react": "^18",
    "react-dom": "^18",
    "semantic-ui-css": "^2.5.0",
    "semantic-ui-react": "^2.1.5",
    "yup": "^1.4.0"
  },
}

Supongamos que tenemos un componente RegisterForm.js con un formulario creado utilizando Semantic UI React en la carpeta src/components/Auth/RegisterForm/:

import { Form } from "semantic-ui-react";
import styles from "./RegisterForm.module.scss";

export function RegisterForm() {
    return (
        <Form>
            <h2 className={styles.heading}>Formulario de Registro</h2>

            <Form.Group widths="equal">
                <Form.Input name="firstName" type="text" placeholder="Nombre" />
                <Form.Input name="lastName" type="text" placeholder="Apellidos" />                
            </Form.Group>

            <Form.Input name="email" type="text" placeholder="Correo electrónico" />

            <Form.Group widths="equal">
                <Form.Input name="username" type="text" placeholder="Nombre de usuario" />
                <Form.Input name="password" type="password" placeholder="Contraseña" />
            </Form.Group>

            <Form.Button type="submit" fluid>
                Registrar
            </Form.Button>
        </Form>
    )
}

Crearemos un archivo RegisterForm.form.js dentro de la misma carpeta y realizaremos las reglas de validación utilizando Yup:

import * as Yup from "yup";

export function initialValues() {
    return {
        firstName: "",
        lastName: "",
        email: "",
        username: "",
        password: ""
    }}

export function validationSchema(){
    return Yup.object({
        firstName: Yup.string().required(true),
        lastName: Yup.string().required(true),
        email: Yup.string().email(true).required(true),
        username: Yup.string().required(true),
        password: Yup.string().required(true),
    });
}

Importamos nuestras dos funciones initialValues() y validationSchema() dentro de nuestro componente RegisterForm.js junto con useFormik

import { initialValues, validationSchema } from "./RegisterForm.form";
import { useFormik } from "formik";

Declaramos una constante de Formik en nuestro componente RegisterForm y le pasamos nuestras funciones.

import { Form } from "semantic-ui-react";
import styles from "./RegisterForm.module.scss";
import { initialValues, validationSchema } from "./RegisterForm.form";
import { useFormik } from "formik";

export function RegisterForm() {

    const formik = useFormik({
        initialValues: initialValues(),
        validationSchema: validationSchema(),
        validateOnChange: false,
        onSubmit: (formValue) => {
            console.log("FORM DATA: ", formValue);
        }
    });

    return (
        ...
    )
}

Le pasamos validateOnChange: false; para evitar que se valide el formulario cuando ocurra algun cambio.

Utilizando nuestra constante formik, pasamos las validaciones a cada uno de nuestros nuestros campos, donde las key name="nombreDelCampo" debe coincidir con los parametros que le pasamos a nuestro objeto initialValues en RegisterForm.form.js:

import { Form } from "semantic-ui-react";
import styles from "./RegisterForm.module.scss";
import { initialValues, validationSchema } from "./RegisterForm.form";
import { useFormik } from "formik";

export function RegisterForm() {

    ...

    return (
        <Form>
             <Form.Input 
                    name="firstName" 
                    type="text" 
                    placeholder="Nombre" 
                    value={formik.values.firstName}
                    onChange={formik.handleChange}
                    error={formik.errors.firstName}
                />
        </Form>
    )
}

Casos especiales

Form.Select

Cuando utilizamos Form.Select debemos manejar el evento onChange de otra manera:

import { Form } from "semantic-ui-react";
import styles from "./RegisterForm.module.scss";
import { initialValues, validationSchema } from "./RegisterForm.form";
import { useFormik } from "formik";

export function RegisterForm() {

    ...

    return (
        <Form>
                <Form.Select 
                    name="gender"
                    label="Género"
                    placeholder="Selecciona tu género"
                    options={genderOptions}
                    onChange={(e, {name, value}) => formik.setFieldValue(name, value)}
                    value={formik.values.gender}
                    error={formik.errors.gender}
                />
        </Form>
    )
}

Luego a nuestro componente Form, en el evento onSubmit, le pasamos el evento formik.handleSubmit:

import { Form } from "semantic-ui-react";
import styles from "./RegisterForm.module.scss";
import { initialValues, validationSchema } from "./RegisterForm.form";
import { useFormik } from "formik";

export function RegisterForm() {

    ...

    return (
        <Form onSubmit={formik.handleSubmit}>
             ...
        </Form>
    )
}

Anteriormente habiamos realizado un console.log, por lo que en este caso, deberías poder ver por consola los parametros que está enviando tu formulario.

(Opcional)

Puedes agregar a tu componente Form.Button, de Semantic UI React, un loading que le indique al usuario que el formulario se está enviando.

Para manejar cuando se ejecutará dicho evento puedes hacer uso del evento formik.isSubmitting:

import { Form } from "semantic-ui-react";
import styles from "./RegisterForm.module.scss";
import { initialValues, validationSchema } from "./RegisterForm.form";
import { useFormik } from "formik";

export function RegisterForm() {

    ...

    return (
        <Form onSubmit={formik.handleSubmit}>
             ...

             <Form.Button type="submit" fluid loading={formik.isSubmitting}>
                Registrar
            </Form.Button>
        </Form>
    )
}
Categor?as