Formularios con React: tutorial paso a paso con Hook Form y MUI

Gabriel Jiménez | Hace alrededor de 1 mes

El objetivo del artículo es aprender las partes esenciales de integrar librerías de creación de formularios como React Hook Form con librerías de estilos como MUI.


Introducción a los formularios en React

Los formularios son de los elementos más utilizados en las aplicaciones frontend: web, móvil y de escritorio. Sin embargo, a veces no se les da la importancia que debería, porque se cree que solo es agregar inputs, ponerlos bonitos y enviaros al backend.


Vamos a ver como esto puede ser un reto y como librerías como React Hook Form y MUI, facilitan su creación.


¿Por qué los formularios son un reto en React?

Para entender que involucra crear un formulario, veamos la figura 1.

Figura 1. Envío de formularios en React


En este flujo los campos y validaciones se inicializan, el usuario ingresa los datos, sincronizados campos con el estado de los campos, ejecutamos validaciones, gestionamos el resultado de las validaciones, formateamos la data antes de enviarla al backend, deshabilitamos acciones mientras la solicitud al backend se procesa y finalmente, damos feedback al usuario sobre el resultado del procesamiento de los datos.
Además de estas tareas, pueda haber otras como:
 
  • Lógica de negocio particular para un conjunto de datos.
  • Validaciones que dependan de otros campos.
  • Validaciones en el backend.
  • Maquetar la página.
  • Diseño responsivo.
  • Mejorar la experiencia de usuario.

La lista puede ir incrementando dependiendo las características del proyecto, por eso librerías como React Hook Form y Material UI son de gran ayuda.


Ventajas de usar librerías como React Hook Form

Las librerías como React Hook Form se encargan de gestionar todo el proceso de envío de formulario — como vimos en la figura 1.


Entre las ventajas que podemos encontrar son:


  • Experiencia del desarrollador (DX). Fácil uso del API.
  • Estándares HTML. Basado en estándares html.
  • Liviano. No requiere ninguna dependencia extra. Solo React y React Hook Form.
  • Rendimiento. Optimiza la cantidad de readers, gestiona eficientemente las validaciones y asegura un montaje rápido.
  • Adoptable. Maneja el estado del formulario internamente, lo que hace que, no se interponga con otros estados internos de otros componentes.
  • Experiencia de usuario (UX). Para mejorar la experiencia de usuario como de las validaciones, aporta continuamente estrategias.

Si quieres saber como crear un formulario con React Hook Form, te invito a leer mi artículo: Tu primer formulario en React con React Hook Form.


Ventajas de usar librerías de estilos como MUI

Las librerías de estilos son muy útiles para agilizar el diseño de nuestras páginas. Muchas de ellas, ya tienen componentes desarrollados con estilos bien definidos, lo que facilita integrarlos en nuestros proyectos. Además que, muchas ya se encargan de la parte responsiva.


Material UI es una librería de estilos muy completa entre sus ventajas tenemos:


  • Fácil personalización. Incluye un amplio conjunto de funciones para personalizar, entre ellas esta el uso de templates.
  • Acelera tu desarrollo. Ellos se encargan de la parte de la interfaz gráfica mientras nosotros en la lógica del negocio.
  • Diseños hermosos. Implementan meticulosamente Material Design en cada uno de sus componentes.
  • Colaboración cross-team. Al tener una excelente experiencia de desarrollo (DX), permite que cualquier involucrado pueda colaborar conjuntamente.
  • Usado por miles de organizaciones. Tiene la comunidad de UI más grande del ecosistema de React.

Configuración inicial del proyecto

Para trabajar este proyecto, utilizaremos Create React App que es una librería para crear aplicaciones React de tipo sigla-page con la más mínima configuración. También, instalaremos React Hook Form y Material UI. 

Crear un proyecto con Create React App

Para crear un proyecto usando Create React App solo hay que ejecutar los siguientes comandos en nuestra terminal.

npx create-react-app my-app
cd my-app
npm start


Al final tendremos una servidor escuchando en el puerto localhost:3000


Instalar dependencias: React Hook Form y Material UI

Para instalar React Hook Form y Material Ui, hay que ejecutar los siguientes comandos:


React Hook Form

npm install react-hook-form


Material UI

npm install @mui/material @emotion/react @emotion/styled


Listo, ya tenemos todo necesario.


Primer formulario con React Hook Form y MUI

Para entender las ventajas de utilizar React Hook Form y MUI, desarrollemos un ejercicio de un formulario sin utilizar ninguna librería externa —únicamente React, y aprendamos que problemas solucionan cada una de estas librerías.


Comencemos implementando el formulario sin librerías externa:

    1: import React from 'react'
    2: 
    3: function App() {
    4:   const [values, setValues] = React.useState({ producto: '', descripcion: '' })
    5:   const [errors, setErrors] = React.useState({})
    6: 
    7:   function validate(v) {
    8:     const e = {}
    9:     if (!v.producto?.trim()) e.producto = 'El producto es obligatorio'
   10:     if (!v.descripcion?.trim()) e.descripcion = 'La descripción es obligatoria'
   11:     return e
   12:   }
   13: 
   14:   function handleChange({ target }) {
   15:     const { value, name } = target
   16:     setValues({ ...values, [name]: value })
   17:   }
   18: 
   19:   function handleSubmit(e) {
   20:     e.preventDefault()
   21:     const eObj = validate(values)
   22:     setErrors(eObj)
   23: 
   24:     if (Object.keys(eObj).length === 0) {
   25:       console.log('Envío de data: ', values)
   26:     }
   27:   }
   28: 
   29:   return (
   30:     <form onSubmit={handleSubmit}>
   31:       <input
   32:         type="text"
   33:         name="producto"
   34:         value={values.producto}
   35:         onChange={handleChange}
   36:         placeholder="Producto"
   37:       />
   38:       {errors.producto && <div>{errors.producto}</div>}
   39: 
   40:       <textarea
   41:         name="descripcion"
   42:         value={values.descripcion}
   43:         onChange={handleChange}
   44:         placeholder="Descripción"
   45:       />
   46:       {errors.descripcion && <div>{errors.descripcion}</div>}
   47: 
   48:       <button type="submit">Enviar</button>
   49:     </form>
   50:   )
   51: }
   52: 
   53: export default App


Este ejemplo es bastante sencillo, pero podemos detectar varios problemas:


  1. Nos encargamos de gestionar lo que el usuario va ingresando con el estado interno.
  2. Definimos el flujo de evaluación de las validaciones.
  3. Si se agregan otros formularios, cada uno puede tener su propia forma de sincronizar lo que el usuario va escribiendo y como gestionar los errores.
  4. Cada campo puede tener estilos diferentes si no se define componentes específicos para cada elemento.



Veamos como React Hook Form y MUI, nos ayuda a solventar estos problemas.

React Hook Form

    1: import React from 'react'
    2: import { useForm } from 'react-hook-form'
    3: 
    4: function App() {
    5:   const { register, handleSubmit, formState: { errors } } = useForm({
    6:     defaultValues: {
    7:       producto: '',
    8:       descripcion: ''
    9:     }
   10:   })
   11: 
   12:   function onSubmit(values) {
   13:     console.log('Envío de data:', values)
   14:   }
   15: 
   16:   return (
   17:     <form onSubmit={handleSubmit(onSubmit)}>
   18:       <input
   19:         type="text"
   20:         {...register('producto', { required: 'El producto es obligatorio' })}
   21:       />
   22:       {errors.producto && <div>{errors.producto.message}</div>}
   23: 
   24:       <textarea
   25:         {...register('descripcion', { required: 'La descripción es obligatoria' })}
   26:       />
   27:       {errors.descripcion && <div>{errors.descripcion.message}</div>}
   28: 
   29:       <button type="submit">Enviar</button>
   30:     </form>
   31:   )
   32: }
   33: 
   34: export default App


Al usar React Hook Form tenemos lineamos para:


  • Inicializar nuestros campos usando el hook useForm
  • Sincronizar lo que el usuario esta escribiendo a través de la función register.
  • Centralizar el flujo de envío del formulario usando handleSubmit.
  • Gestionar los errores usando el objeto formState.

Material UI

    1: import React from 'react'
    2: import { useForm } from 'react-hook-form'
    3: import TextField from '@mui/material/TextField'
    4: import Button from '@mui/material/Button'
    5: 
    6: function App() {
    7:   const { register, handleSubmit, formState: { errors } } = useForm({
    8:     defaultValues: {
    9:       producto: '',
   10:       descripcion: ''
   11:     }
   12:   })
   13: 
   14:   function onSubmit(values) {
   15:     console.log('Envío de data:', values)
   16:   }
   17: 
   18:   return (
   19:     <form onSubmit={handleSubmit(onSubmit)}>
   20:       <TextField
   21:         label="Producto"
   22:         {...register('producto', { required: 'El producto es obligatorio' })}
   23:         error={!!errors.producto}
   24:         helperText={errors.producto?.message}
   25:       />
   26: 
   27:       <TextField
   28:         label="Descripción"
   29:         multiline
   30:         rows={3}
   31:         {...register('descripcion', { required: 'La descripción es obligatoria' })}
   32:         error={!!errors.descripcion}
   33:         helperText={errors.descripcion?.message}
   34:       />
   35: 
   36:       <Button type="submit" variant="contained">
   37:         Enviar
   38:       </Button>
   39:     </form>
   40:   )
   41: }
   42: 
   43: export default App


Perfecto, ahora ya tenemos componentes con un mismo estilo.


Para mantener un estándar de estilos en nuestras aplicaciones, podemos usar los templates o encapsular la estructura de estilos en un nuevo componente, por ejemplo:

const MiTextArea = ({...muiProps }) => {
  return(
    <TextField
      { ... muiProps }
      multiline
      rows={3}
    />
  )
}


De esta forma, establecemos que siempre los TextArea tendrán tres filas.


Si quieres aprender a crear formularios más escalables, revisa mi artículo: Formulario en React con MUI, guía para principiantes.


Conclusión

Al utilizar librerías de terceros podemos agilizar nuestros desarrollos, al facilitar lineamos bien estructurados para formularios. Sin embargo, es importante diseñar antes de implementar en nuestros proyectos.


Para aprender más sobre cómo crear formularios más avanzados, te recomiendo mi libro: Testing en React: Guía práctica con Jest y React Testing Library.