No hay duda de que los formularios web juegan un papel integral en nuestro sitio web o aplicaciones. De forma predeterminada, proporcionan un conjunto útil de elementos y características, desde leyendas y conjuntos de campos hasta validaciones y estados nativos, pero solo nos llevan hasta cierto punto cuando comenzamos a considerar las peculiaridades de su uso. Por ejemplo, ¿cómo podemos manipular el estado de una forma? ¿Qué hay de las diferentes formas de validación? Incluso conectar un formulario para publicar envíos es a veces un esfuerzo desalentador.
Las bibliotecas front-end impulsadas por componentes, como React, pueden facilitar la tarea de conectar formularios web, pero también pueden volverse detalladas y redundantes. Por eso quiero presentarte Formik, una pequeña biblioteca que resuelve las tres partes más molestas de las formas de escritura en React:
- Manipulación del estado
- Validación de formularios (y mensajes de error)
- Envío de formulario
Vamos a crear un formulario juntos en esta publicación. Comenzaremos con un componente React y luego integraremos Formik mientras demostramos la forma en que maneja el estado, la validación y los envíos.
Crear un formulario como componente de React
Los componentes viven y respiran a través de su Expresar y apuntalar. Lo que los elementos de formulario HTML tienen en común con los componentes de React es que, naturalmente, mantienen algún estado interno. Sus valores también se almacenan automáticamente en su atributo de valor.
Permitir que los elementos de formulario administren su propio estado en React los convierte en componentes no controlados. Esa es solo una forma elegante de decir que DOM maneja el estado en lugar de React. Y mientras eso funciona, a menudo es más fácil usar componentes controlados, donde React maneja el estado y sirve como la única fuente de verdad en lugar del DOM.
El marcado para un formulario HTML sencillo podría verse así:
<form>
<div className="formRow">
<label htmlFor="email">Email address</label>
<input type="email" name="email" className="email" />
</div>
<div className="formRow">
<label htmlFor="password">Password</label>
<input type="password" name="password" className="password" />
</div>
<button type="submit">Submit</button>
</form>
Podemos convertir eso en un componente React controlado así:
function HTMLForm() {
const [email, setEmail] = React.useState("");
const [password, setPassword] = React.useState("");
return (
<form>
<div className="formRow">
<label htmlFor="email">Email address</label>
<input
type="email"
name="email"
className="email"
value={email}
onChange={e => setEmail(e.target.value)}
/>
</div>
<div className="formRow">
<label htmlFor="password">Password</label>
<input
type="password"
name="password"
className="password"
value={password}
onChange={e => setPassword(e.target.value)}
/>
</div>
<button type="submit">Submit</button>
</form>
);
}
Esto es un poco detallado, pero tiene algunos beneficios:
- Obtenemos una única fuente de verdad para los valores de forma en el estado.
- Podemos validar el formulario cuando y como queramos.
- Obtenemos ventajas de rendimiento cargando lo que necesitamos y cuando lo necesitamos.
Bien, entonces, ¿por qué Formik de nuevo?
Como ocurre con cualquier JavaScript, ya existe una gran cantidad de bibliotecas de administración de formularios, como React Hook Form y Redux Form, que podemos usar. Pero hay varias cosas que hacen que Formik se destaque del resto:
- Es declarativo: Formik elimina la redundancia mediante la abstracción y la responsabilidad del estado, la validación y las presentaciones.
- Ofrece una escotilla de escape: La abstracción es buena, pero las formas son propias de ciertos patrones. Formik resúmenes para usted, pero también le permite controlarlo si lo necesita.
- Ubica estados de formulario: Formik mantiene todo lo que tiene que ver con su formulario dentro de los componentes de su formulario.
- Es adaptable: Formik no te impone ninguna regla. Puede usar tanto Formik como necesite.
- Fácil de usar: Formik simplemente funciona.
¿Suena bien? Implementemos Formik en nuestro componente de formulario.
Yendo a Formik
Crearemos un formulario de inicio de sesión básico para mojarnos los picos con los fundamentos. Hablaremos de tres formas diferentes de trabajar con Formik:
- Utilizando el
useFormik
gancho - Utilizando
Formik
con contexto React - Utilizando
withFormik
como un componente de orden superior
Creé una demostración con los paquetes que necesitamos, Formik y Yup.
Método 1: usar el gancho useFormik
Como está ahora, nuestra forma no hace nada tangible. Para comenzar a usar Formik, necesitamos importar el useFormik
gancho. Cuando usamos el gancho, devuelve todas las funciones y variables de Formik que nos ayudan a administrar el formulario. Si tuviéramos que registrar los valores devueltos en la consola, obtenemos esto:
Llamaremos useFormik
y pásalo initialValues
para comenzar. Entonces, un onSubmit
El controlador se activa cuando se envía un formulario. Así es como se ve eso:
// This is a React component
function BaseFormik() {
const formik = useFormik({
initialValues: {
email: "",
password: ""
},
onSubmit(values) {
// This will run when the form is submitted
}
});
// If you're curious, you can run this Effect
// useEffect(() => {
// console.log({formik});
// }, [])
return (
// Your actual form
)
}
Luego vincularemos Formik a nuestros elementos de formulario:
// This is a React component
function BaseFormik() {
const formik = useFormik({
initialValues: {
email: "",
password: ""
},
onSubmit(values) {
// This will run when the form is submitted
}
});
// If you're curious, you can run this Effect
// useEffect(() => {
// console.log({formik});
// }, [])
return (
// We bind "onSubmit" to "formik.handleSubmit"
<form className="baseForm" onSubmit={formik.handleSubmit} noValidate>
<input
type="email"
name="email"
id="email"
className="email formField"
value={formik.values.email} // We also bind our email value
onChange={formik.handleChange} // And, we bind our "onChange" event.
/>
</form>
)
}
Así es como funciona la encuadernación:
- Maneja el envío de formularios con
onSubmit={formik.handleSubmit}
. - Maneja el estado de las entradas con
value={formik.values.email}
yonChange={formik.handleChange}
.
Si miras más de cerca, no tuvimos que configurar nuestro estado, ni manejar el onChange
o onSubmit
eventos como lo haríamos normalmente con React.
Sin embargo, como habrá notado, nuestro formulario contiene algunas redundancias. Tuvimos que profundizar en formik y vincular manualmente las entradas del formulario value
y onChange
evento. Eso significa que debemos desestructurar el valor devuelto e inmediatamente vincular los accesorios necesarios a un campo dependiente, como este:
// This is a React component
function BaseFormik() {
const {getFieldProps, handleSubmit} = useFormik({
initialValues: {
email: "",
password: ""
},
onSubmit(values) {
// This will run when the form is submitted
}
});
// If you're curious, you can run this Effect
// useEffect(() => {
// console.log({formik});
// }, [])
return (
<form className="baseForm" onSubmit={handleSubmit} noValidate>
<input
type="email"
id="email"
className="email formField"
{...getFieldProps("email")} // We pass the name of the dependent field
/>
</form>
)
}
Llevemos las cosas aún más lejos con el <Formik/>
componente.
Método 2: usar Formik con el contexto de React
El <Formik/>
El componente expone varios otros componentes que agregan más abstracción y valores predeterminados sensibles. Por ejemplo, componentes como <Form/
>, <Field/>
, y <ErrorMessage/>
están listos para salir de la caja.
Tenga en cuenta que no es necesario que utilice estos componentes cuando trabaje con <Formik/>
pero requieren <Formik/>
(o withFormik
) al usarlos.
Utilizando <Formik/>
requiere una revisión porque utiliza el patrón de accesorios de renderizado en lugar de ganchos con useFormik
. El patrón de accesorios de renderizado no es algo nuevo en React. Es un patrón que permite la reutilización del código entre componentes, algo que los ganchos resuelven mejor. Sin embargo, <Formik/>
tiene una bolsa llena de componentes personalizados que facilitan mucho el trabajo con formularios.
import { Formik } from "formik";
function FormikRenderProps() {
const initialValues = {
email: "",
password: ""
};
function onSubmit(values) {
// Do stuff here...
alert(JSON.stringify(values, null, 2));
}
return (
<Formik {...{ initialValues, onSubmit }}>
{({ getFieldProps, handleSubmit }) => (
<form className="baseForm" onSubmit={handleSubmit} noValidate>
<input
type="email"
id="email"
className="email formField"
{...getFieldProps("email")}
/>
</form>
)}
</Formik>
);
}
Darse cuenta de initialValues
y onSubmit
han sido completamente separados de useFormik
. Esto significa que podemos pasar los accesorios que <Formik/>
necesidades, específicamente initialValues
y useFormik
.
<Formik/>
devuelve un valor que se ha desestructurado en getFieldProps
y handleSubmit
. Todo lo demás básicamente sigue siendo el mismo que el primer método que usa useFormik
.
Aquí hay un repaso sobre los accesorios de renderizado de React si se siente un poco oxidado.
En realidad, no hemos puesto ninguna <Formik/>
componentes para usar por el momento. Hice esto intencionalmente para demostrar la adaptabilidad de Formik. Ciertamente queremos usar esos componentes para nuestros campos de formulario, así que reescribamos el componente para que use el <Form/>
componente.
import { Formik, Field, Form } from "formik";
function FormikRenderProps() {
const initialValues = {
email: "",
password: ""
};
function onSubmit(values) {
// Do stuff here...
alert(JSON.stringify(values, null, 2));
}
return (
<Formik {...{ initialValues, onSubmit }}>
{() => (
<Form className="baseForm" noValidate>
<Field
type="email"
id="email"
className="email formField"
name="email"
/>
</Form>
)}
</Formik>
);
}
Fueron puestos <form/>
con <Form/>
y quitó el onSubmit
controlador ya que Formik se encarga de eso por nosotros. Recuerde, asume todas las responsabilidades de manejo de formularios.
También reemplazamos <input/>
con <Field/>
y quitó las fijaciones. Una vez más, Formik se encarga de eso.
Tampoco hay necesidad de preocuparse por el valor devuelto por <Formik/>
nunca más. Lo adivinaste, Formik también se encarga de eso.
Formik se encarga de todo por nosotros. Ahora podemos centrarnos más en la lógica empresarial de nuestros formularios que en cosas que esencialmente se pueden abstraer.
Estamos listos para ir y ¿adivinen qué? ¡No nos han preocupado las administraciones estatales o los envíos de formularios!
“¿Qué pasa con la validación?” Tu puedes preguntar. No hemos hablado de eso porque es un nivel completamente nuevo por sí solo. Toquemos eso antes de pasar al último método.
Validación de formularios con Formik
Si alguna vez ha trabajado con formularios (y apuesto a que sí), entonces es consciente de que la validación no es algo que deba descuidarse.
Queremos tomar el control de cuándo y cómo validar para que se abran nuevas oportunidades para crear mejores experiencias de usuario. Gmail, por ejemplo, no le permitirá ingresar una contraseña a menos que la entrada de la dirección de correo electrónico esté validada y autenticada. También podríamos hacer algo en el que validamos en el lugar y mostramos mensajes sin interacciones adicionales o actualizaciones de página.
Aquí hay tres formas en que Formik puede manejar la validación:
- A nivel de formulario
- A nivel de campo
- Con gatillos manuales
La validación a nivel de formulario significa validar el formulario como un todo. Dado que tenemos acceso inmediato a los valores del formulario, podemos validar el formulario completo de una vez:
- utilizando
validate
, o - usando una biblioteca de terceros con
validationSchema
.
Ambos validate
y validationSchema
son funciones que devuelven un errors
objeto con pares clave / valor que los de initialValues
. Podemos pasarlos a useFormik
, <Formik/>
o withFormik
.
Mientras validate
se utiliza para validaciones personalizadas, validationSchema
se usa con una biblioteca de terceros como Yup.
Aquí hay un ejemplo usando validate
:
// Pass the `onSubmit` function that gets called when the form is submitted.
const formik = useFormik({
initialValues: {
email: "",
password: ""
},
// We've added a validate function
validate() {
const errors = {};
// Add the touched to avoid the validator validating all fields at once
if (formik.touched.email && !formik.values.email) {
errors.email = "Required";
} else if (
!/^[A-Z0-9._%+-][email protected][A-Z0-9.-]+.[A-Z]{2,4}$/i.test(formik.values.email)
) {
errors.email = "Invalid email address";
}
if (formik.touched.password && !formik.values.password) {
errors.password = "Required";
} else if (formik.values.password.length <= 8) {
errors.password = "Must be more than 8 characters";
}
return errors;
},
onSubmit(values) {
// Do stuff here...
}
});
// ...
Y aquí vamos con un ejemplo usando validationSchema
en lugar de:
const formik = useFormik({
initialValues: {
email: "",
password: ""
},
// We used Yup here.
validationSchema: Yup.object().shape({
email: Yup.string()
.email("Invalid email address")
.required("Required"),
password: Yup.string()
.min(8, "Must be more than 8 characters")
.required("Required")
}),
onSubmit(values) {
// Do stuff here...
}
});
La validación a nivel de campo o el uso de activadores manuales son bastante fáciles de entender. Sin embargo, es probable que utilice la validación de nivel de formulario la mayor parte del tiempo. También vale la pena consultar los documentos para ver otros casos de uso.
Método 3: usar withFormik como un componente de orden superior
withFormik
es un componente de orden superior y se puede usar de esa manera si eso es lo tuyo. Escriba el formulario, luego expóngalo a través de Formik.
Un par de ejemplos prácticos
Hasta ahora, nos hemos familiarizado con Formik, cubrimos los beneficios de usarlo para crear formularios en React y cubrimos algunos métodos para implementarlo como un componente de React mientras demostramos varias formas en que podemos usarlo para la validación. Lo que no hemos hecho es analizar ejemplos de esos conceptos clave.
Entonces, veamos un par de aplicaciones prácticas: mostrar mensajes de error y generar un nombre de usuario basado en lo que ingresó en la entrada del correo electrónico.
Visualización de mensajes de error
Hemos construido nuestro formulario y lo hemos validado. Y hemos detectado algunos errores que se pueden encontrar en nuestro errors
objeto. Pero no sirve de nada si no estamos mostrando esos errores.
Formik hace que esta sea una tarea bastante trivial. Todo lo que tenemos que hacer es comprobar el errors
objeto devuelto por cualquiera de los métodos que hemos visto: <Formik/>
, useFormik
o withFormik
– y mostrarlos:
<label className="formFieldLabel" htmlFor="email">
Email address
<span className="errorMessage">
{touched["email"] && errors["email"]}
</span>
</label>
<div className="formFieldWrapInner">
<input
type="email"
id="email"
className="email formField"
{...getFieldProps("email")}
/>
</div>
Si hay un error durante la validación, {touched["email"] && errors["email"]}
se lo mostrará al usuario.
Podríamos hacer lo mismo con <ErrorMessage/>
. Con esto, solo necesitamos decirle el nombre del campo dependiente a vigilar:
<ErrorMessage name="email">
{errMsg => <span className="errorMessage">{errMsg}</span>}
</ErrorMessage>
Generando un nombre de usuario a partir de una dirección de correo electrónico
Imagine un formulario que genera automáticamente un nombre de usuario para sus usuarios en función de su dirección de correo electrónico. En otras palabras, lo que sea que el usuario escriba en la entrada del correo electrónico se extrae, se elimina @
y todo lo que sigue, y nos deja con un nombre de usuario con lo que queda.
Por ejemplo: [email protected]
produce @jane
.
Formik expone ayudantes que pueden “interceptar” su funcionalidad y nos permite realizar algunos efectos. En el caso de autogenerar un nombre de usuario, una forma será a través de Formik setValues
:
onSubmit(values) {
// We added a `username` value for the user which is everything before @ in their email address.
setValues({
...values,
username: `@${values.email.split("@")[0]}`
});
}
Escriba una dirección de correo electrónico y una contraseña, luego envíe el formulario para ver su nuevo nombre de usuario.
Terminando
Vaya, cubrimos mucho terreno en poco espacio. Si bien esto es solo la punta del iceberg en cuanto a cubrir todas las necesidades de un formulario y lo que Formik es capaz de hacer, espero que esto le brinde una nueva herramienta para la próxima vez que se encuentre abordando formularios en una aplicación React. .
Si está listo para llevar a Formik al siguiente nivel, le sugiero que consulte sus recursos como punto de partida. Hay tantos beneficios allí y es un buen archivo de lo que Formik puede hacer, así como más tutoriales que se adentran en casos de uso más profundos.
¡Buena suerte con tus formularios!