Hace unos días solicité un trabajo de desarrollador front-end y tuve noticias de la empresa. Siguieron con un correo electrónico y querían que completara un desafío de codificación de React en HackerRank como parte del proceso de entrevista. La prueba constaba de solo dos preguntas y se refería a React.
Suena bastante fácil, ¿verdad?
La prueba se cronometró y solo permitió unos 20 minutos de tiempo para corregir un formulario semiconstruido proporcionado y para agregar la validación del formulario para los formularios de entrada de nombre , correo electrónico , número de teléfono y URL . Después de tropezar con esta tarea y quedarme sin tiempo, decidí que era hora de buscar bibliotecas de validación de formularios para crear y validar formularios con React.
Decidí aprender a usar Formik y Yup para validar formularios.
En este artículo, le mostraré cómo crear un formulario simple y directo con Formik y Yup para la funcionalidad y la validación, y React-Bootstrap para la interfaz de usuario.
Este artículo asume que el lector está familiarizado con React , create-react-app y npm . Este artículo no analizará los entresijos de la creación de un formulario o estilo básico, el enfoque estará en la validación de formularios con Formik y Yup .
Primero instalemos React-Bootstrap y Styled-Components con npm :
npm install react-bootstrap bootstrapnpm install react-bootstrap bootstrap
npm i styled-components
Después de instalar React-Bootstrap e incluir la hoja de estilo en nuestro
index.html
archivo, construyamos un formulario básico usando React-Bootstrap que incluye una entrada de nombre, correo electrónico, teléfono y URL: import React from 'react'; import styled from 'styled-components'; import { Form , Button } from 'react- bootstrap '; // Styled-components styles const CONTAINER = styled.div` background: #F7F9FA; height: auto; width: 90%; margin: 5em auto; color: snow; -webkit-box-shadow: 5px 5px 5px 0px rgba(0, 0, 0, 0.4); -moz-box-shadow: 5px 5px 5px 0px rgba(0, 0, 0, 0.4); box-shadow: 5px 5px 5px 0px rgba(0, 0, 0, 0.4); @media(min-width: 786px) { width: 60%; } label { color: #24B9B6; font-size: 1.2em; font-weight: 400; } h1 { color: #24B9B6; padding-top: .5em; } . form -group { margin-bottom: 2.5em; } `; const MYFORM = styled( Form )` width: 90%; text-align: left; padding-top: 2em; padding-bottom: 2em; @media(min-width: 786px) { width: 50%; } `; const BUTTON = styled(Button)` background: #1863AB; border: none; font-size: 1.2em; font-weight: 400; &:hover { background: #1D3461; } `; const BasicForm = () => { return ( <CONTAINER> <MYFORM className= "mx-auto" > < Form .Group controlId= "formName" > < Form . Label >Name :</ Form . Label > < Form .Control type = "text" name= "name" placeholder= "Full Name" /> </ Form .Group> < Form .Group controlId= "formEmail" > < Form . Label >Email :</ Form . Label > < Form .Control type = "text" name= "email" placeholder= "Email" /> </ Form .Group> < Form .Group controlId= "formPhone" > < Form . Label >Phone :</ Form . Label > < Form .Control type = "text" name= "phone" placeholder= "Phone" /> </ Form .Group> < Form .Group controlId= "formBlog" > < Form . Label >Blog :</ Form . Label > < Form .Control type = "text" name= "blog" placeholder= "Blog URL" /> </ Form .Group> <BUTTON variant= "primary" type = "submit" > Submit </BUTTON> </MYFORM> </CONTAINER> ); } export default BasicForm;
Así es como se ve nuestro formulario:
Ahora que nuestro formulario de contacto básico está construido, instalemos Formik y Yup y comencemos a construir las funciones de validación:
npm i formik
npm i yup
Formik nos brinda acceso a una gran cantidad de funciones relacionadas con los formularios, como el almacenamiento de los valores de los formularios de entrada, el manejo de errores , la funcionalidad onSubmit y la validación . Sí , es solo un " validador de esquema de objeto " que combina muy bien con Formik y se usará para validar los campos de entrada en el formulario.
Después de importar Formik y Yup en nuestro componente React , lo primero que debemos hacer es envolver el formulario dentro de un
<Formik>
etiqueta. Después de envolver el formulario dentro del <Formik>
etiqueta estableceremos los valores iniciales de las entradas del formulario utilizando Formik initialValues
apuntalar.Esto consiste en configurar un objeto que contenga todos los valores iniciales de partida para nuestro formulario, así:
//Sets initial values for form inputs <Formik initialValues={{ name: "" , email: "" , phone: "" , blog: "" }}>
Después de establecer todos los valores iniciales, necesitamos llamar a una función dentro del
Formik
etiqueta. La documentación de Formik enumera una larga lista de ayudantes disponibles. En nuestro caso usaremos values
, errors
, touched
, handleChange
, handleBlur
, handleSubmit
, & isSubmitting
.Después de inicializar nuestro formulario y llamar a la función de devolución de llamada con los parámetros necesarios, nuestro formulario se ve así:
const BasicForm = () => { return ( <CONTAINER> //Sets initial values for form inputs <Formik initialValues={{ name: "" , email: "" , phone: "" , blog: "" }}> { /* Callback function containing Formik state and helpers that handle common form actions */ } {( {values, errors, touched, handleChange, handleBlur, handleSubmit, isSubmitting }) => ( <MYFORM className= "mx-auto" > < Form .Group controlId= "formName" > < Form . Label >Name :</ Form . Label > < Form .Control type = "text" name= "name" placeholder= "Full Name" /> </ Form .Group> < Form .Group controlId= "formEmail" > < Form . Label >Email :</ Form . Label > < Form .Control type = "text" name= "email" placeholder= "Email" /> </ Form .Group> < Form .Group controlId= "formPhone" > < Form . Label >Phone :</ Form . Label > < Form .Control type = "text" name= "phone" placeholder= "Phone" /> </ Form .Group> < Form .Group controlId= "formBlog" > < Form . Label >Blog :</ Form . Label > < Form .Control type = "text" name= "blog" placeholder= "Blog URL" /> </ Form .Group> <BUTTON variant= "primary" type = "submit" > Submit </BUTTON> </MYFORM> )} </Formik> </CONTAINER> ); } export default BasicForm;
Ahora que nuestros valores están inicializados y nuestra función de devolución de llamada contiene los parámetros adecuados, actualicemos los formularios de campo y conéctelos a Formik agregando
onChange
, onBlur
, y value
a nuestras propiedades de formulario: const BasicForm = () => { return ( <CONTAINER> //Sets initial values for form inputs <Formik initialValues={{ name: "" , email: "" , phone: "" , blog: "" }}> { /* Callback function containing Formik state and helpers that handle common form actions */ } {( {values, errors, touched, handleChange, handleBlur, handleSubmit, isSubmitting }) => ( <MYFORM className= "mx-auto" > {console. log (values)} < Form .Group controlId= "formName" > < Form . Label >Name :</ Form . Label > < Form .Control type = "text" /* This name property is used to access the value of the form element via values.nameOfElement */ name= "name" placeholder= "Full Name" /* Set onChange to handleChange */ onChange={handleChange} /* Set onBlur to handleBlur */ onBlur={handleBlur} /* Store the value of this input in values.name, make sure this is named the same as the name property on the form element */ value={values.name} /> </ Form .Group> < Form .Group controlId= "formEmail" > < Form . Label >Email :</ Form . Label > < Form .Control type = "text" name= "email" placeholder= "Email" onChange={handleChange} onBlur={handleBlur} value={values.email} /> </ Form .Group> < Form .Group controlId= "formPhone" > < Form . Label >Phone :</ Form . Label > < Form .Control type = "text" name= "phone" placeholder= "Phone" onChange={handleChange} onBlur={handleBlur} value={values.phone} /> </ Form .Group> < Form .Group controlId= "formBlog" > < Form . Label >Blog :</ Form . Label > < Form .Control type = "text" name= "blog" placeholder= "Blog URL" onChange={handleChange} onBlur={handleBlur} value={values.blog} /> </ Form .Group> <BUTTON variant= "primary" type = "submit" > Submit </BUTTON> </MYFORM> )} </Formik> </CONTAINER> ); } export default BasicForm;
Fíjate que podemos
console.log(values)
y esto cerrará la sesión de todos los valores en nuestro formulario.Después de completar las entradas del formulario, se registra lo siguiente en la consola:
Nuestro formulario React-Bootstrap ahora está conectado a Formik y Formik está manejando los datos de entrada por nosotros. El siguiente paso es agregar validación a nuestro formulario, aquí es donde entra en juego Yup .
Usando Yup , podemos crear un esquema de objeto que le dice a nuestro formulario qué forma deben tener nuestros datos y los requisitos que queremos que tenga cada campo de entrada cuando se valida (es decir, los correos electrónicos deben estar en [email protected] formato o nombres que deben contener al menos dos letras).
Para usar Yup crearemos un
validationSchema
variable y configúrelo igual a una función que llama a Yup's Object
y Shape
métodos. Shape
contendrá un objeto que contiene los nombres de entrada del formulario ( nombre , correo electrónico , teléfono , blog ). Esto nos permitirá usar Yup para establecer reglas de validación para nuestros elementos ingresados y se ve así: // Schema for yup const validationSchema = Yup . object () .shape({ name: Yup . string () , email: Yup . string () , phone: Yup . string () , blog: Yup . string () });
ValidationSchema contiene una propiedad para cada uno de nuestros elementos de formulario y
Yup.string()
le dice a la forma que estos elementos deben ser de tipo string
. Sí , ofrece muchas funciones diferentes para validar campos de formulario.Por el bien de este formulario, usaremos
min
, max
, required
, email
, matches
, y url
. Consulte la documentación de Yup para ver más funciones disponibles. min
y max
permitirnos establecer longitudes mínimas y máximas para el texto ingresado, required
nos permite hacer un campo obligatorio, email
requiere que la entrada esté en un formato de correo electrónico válido (es decir, [email protected] ), y url
requiere que la entrada sea una URL válida (es decir, http://www.website.com ). Matches
nos permite pasar una variable que contiene una expresión regular y verificar que los datos del formulario ingresado coincidan. Usaremos matches
y una expresión regular para verificar el formato de los datos del formulario del teléfono.Todas estas funciones de validación nos permiten pasar un mensaje de error como segundo parámetro.
El objeto de esquema de validación completo se ve así:
// RegEx for phone number validation const phoneRegExp = /^(\+?\d{ 0 , 4 })?\s?-?\s?(\(?\d{ 3 }\)?)\s?-?\s?(\(?\d{ 3 }\)?)\s?-?\s?(\(?\d{ 4 }\)?)?$/ // Schema for yup const validationSchema = Yup . object () .shape({ name: Yup . string () .min( 2 , "*Names must have at least 2 characters" ) .max( 100 , "*Names can't be longer than 100 characters" ) .required( "*Name is required" ), email: Yup . string () .email( "*Must be a valid email address" ) .max( 100 , "*Email must be less than 100 characters" ) .required( "*Email is required" ), phone: Yup . string () .matches(phoneRegExp, "*Phone number is not valid" ) .required( "*Phone number required" ), blog: Yup . string () .url( "*Must enter URL in http://www.example.com format" ) .required( "*URL required" ) });
Formik proporciona a nuestro formulario un accesorio de esquema de validación y podemos usar nuestra variable Validación de esquema Yup para pasar nuestro esquema a nuestro formulario de esta manera:
<Formik initialValues={{ name: "" , email: "" , phone: "" , blog: "" }} // Hooks up our validationSchema to Formik validationSchema={validationSchema} >
Ahora el formulario está configurado para realizar la validación usando el
validationSchema
esquema Si queremos cambiar el cuadro de entrada del formulario a rojo cuando el usuario ingresa datos que no pasan nuestras pruebas de validación definidas por validationSchema
, podemos agregar una clase CSS para hacer eso y usar un operador ternario para probar si hay un error y aplicar la clase en caso de que haya un error: <Form.Control type= "text" /* This name property is used to access the value of the form element via values.nameOfElement */ name = "name" placeholder= "Full Name" /* Set onChange to handleChange */ onChange={handleChange} /* Set onBlur to handleBlur */ onBlur={handleBlur} /* Store the value of this input in values. name , make sure this is named the same as the name property on the form element */ value={values. name } /* Check if the name field (this field) has been touched and if there is an error , if so add the . error class styles defined in the CSS (make the input box red) */ className={touched. name && errors. name ? "error" : null} />
los
touched
property es uno de los parámetros llamados en nuestro Formik
función de devolución de llamada y prueba si el usuario ha hecho clic en ese elemento en particular. {touched.name && errors.name ? "error" : null}
prueba si el usuario ha hecho clic en el campo de entrada de nombre y si hay un error al validar los datos ingresados. Si hay un error, aplicamos la clase de error al elemento y en nuestro CSS cambiamos el borde del cuadro de entrada a rojo.Este operador ternario aplicará esta clase CSS recién agregada que vuelve rojo el cuadro de entrada:
.error { border : 2px solid #FF6565 ; }
Ahora, cuando un usuario ingresa texto que no pasa nuestras pruebas de validación, el cuadro de entrada se vuelve rojo:
Anteriormente en nuestro
validationSchema
cuando usamos Yup para establecer reglas para la validación, incluimos mensajes de error para mostrar la explicación del error de entrada al usuario. ¿Cómo hacemos para mostrar el mensaje de error en el elemento de formulario al que pertenece?Podemos usar el
touch
objeto y el errors
objeto proporcionado a nuestro formulario por Formik en la función de devolución de llamada junto con un operador ternario para mostrar el mensaje de error apropiado: {touched.name && errors.name ? ( < div className = "error-message" > {errors.name} </ div > ): null }
Este operador ternario aplicará esta clase CSS recién agregada que maneja el estilo del mensaje de error:
.error-message { color : #FF6565 ; padding : . 5em . 2em ; height : 1em ; position : absolute; font-size : . 8em ; }
Al agregar un operador ternario con las pruebas apropiadas para cada entrada de formulario, podemos agregar el mensaje de error correcto de
validateSchema
para cada entrada de formulario.El formulario completo y el esquema ahora se ven así:
// RegEx for phone number validation const phoneRegExp = /^(\+?\ d {0,4})?\s?-?\s?(\(?\ d {3}\)?)\s?-?\s?(\(?\ d {3}\)?)\s?-?\s?(\(?\ d {4}\)?)?$/ // Schema for yup const validationSchema = Yup.object().shape({ name: Yup. string () . min (2, "*Names must have at least 2 characters" ) . max (100, "*Names can't be longer than 100 characters" ) .required( "*Name is required" ), email: Yup. string () .email( "*Must be a valid email address" ) . max (100, "*Email must be less than 100 characters" ) .required( "*Email is required" ), phone: Yup. string () .matches(phoneRegExp, "*Phone number is not valid" ) .required( "*Phone number required" ), blog: Yup. string () .url( "*Must enter URL in http://www.example.com format" ) .required( "*URL required" ) }); const BasicForm = () => { return ( <CONTAINER> //Sets initial values for form inputs <Formik initialValues={{ name: "" , email: "" , phone: "" , blog: "" }} // Hooks up our validationSchema to Formik validationSchema={validationSchema} > { /* Callback function containing Formik state and helpers that handle common form actions */ } {( {values, errors, touched, handleChange, handleBlur, handleSubmit, isSubmitting }) => ( <MYFORM className= "mx-auto" > {console. log (values)} < Form .Group controlId= "formName" > < Form . Label >Name :</ Form . Label > < Form .Control type = "text" /* This name property is used to access the value of the form element via values.nameOfElement */ name= "name" placeholder= "Full Name" /* Set onChange to handleChange */ onChange={handleChange} /* Set onBlur to handleBlur */ onBlur={handleBlur} /* Store the value of this input in values.name, make sure this is named the same as the name property on the form element */ value={values.name} /* Check if the name field (this field) has been touched and if there is an error, if so add the .error class styles defined in the CSS (make the input box red) */ className={touched.name && errors.name ? "error" : null} /> { /* Applies the proper error message from validateSchema when the user has clicked the element and there is an error, also applies the .error-message CSS class for styling */ } {touched.name && errors.name ? ( <div className= "error-message" >{errors.name}</div> ): null} </ Form .Group> < Form .Group controlId= "formEmail" > < Form . Label >Email :</ Form . Label > < Form .Control type = "text" name= "email" placeholder= "Email" onChange={handleChange} onBlur={handleBlur} value={values.email} className={touched.email && errors.email ? "error" : null} /> {touched.email && errors.email ? ( <div className= "error-message" >{errors.email}</div> ): null} </ Form .Group> < Form .Group controlId= "formPhone" > < Form . Label >Phone :</ Form . Label > < Form .Control type = "text" name= "phone" placeholder= "Phone" onChange={handleChange} onBlur={handleBlur} value={values.phone} className={touched.phone && errors.phone ? "error" : null} /> {touched.phone && errors.phone ? ( <div className= "error-message" >{errors.phone}</div> ): null} </ Form .Group> < Form .Group controlId= "formBlog" > < Form . Label >Blog :</ Form . Label > < Form .Control type = "text" name= "blog" placeholder= "Blog URL" onChange={handleChange} onBlur={handleBlur} value={values.blog} className={touched.blog && errors.blog ? "error" : null} /> {touched.blog && errors.blog ? ( <div className= "error-message" >{errors.blog}</div> ): null} </ Form .Group> <BUTTON variant= "primary" type = "submit" > Submit </BUTTON> </MYFORM> )} </Formik> </CONTAINER> ); } export default BasicForm;
Ahora, cuando un usuario ingresa datos que no pasan nuestra prueba de validación, se muestra el mensaje de error que definimos anteriormente en el esquema .
El resultado final se ve así:
Por último, pero no menos importante, nuestro formulario debe enviarse cuando el usuario hace clic en el botón Enviar. Formik nos proporciona una
onSubmit
prop que se encarga de esto. pasamos el onSubmit
apoyar los valores y también setSubmitting
y resetForm
. setSubmitting
se establecerá en verdadero cuando el usuario envíe el formulario y resetForm
se llamará después de que se envíe el formulario para borrar el envío posterior del formulario.Nuestra etiqueta Formik , con un
onSubmit
la función ahora se ve así: <Formik initialValues={{ name: "" , email: "" , phone: "" , blog: "" }} validationSchema={validationSchema} onSubmit={(values, {setSubmitting, resetForm}) => { // When button submits form and form is in the process of submitting, submit button is disabled setSubmitting( true ); // Resets form after submission is complete resetForm(); // Sets setSubmitting to false after form is reset setSubmitting( false ); }} >
Para llamar a este
onSubmit
función nuestra forma tiene que tener un onSubmit
conjunto de accesorios para handleSubmit
: < MYFORM onSubmit = {handleSubmit} className = "mx-auto" >
Además de manejar el envío del formulario, también podemos deshabilitar el botón de envío mientras se envía el formulario, de modo que después de que el usuario haga clic en enviar, el botón de envío esté deshabilitado mientras el formulario está en proceso de envío.
Hacemos esto agregando una propiedad deshabilitada al botón y estableciéndolo igual a
isSubmitting
: < BUTTON variant = "primary" type = "submit" disabled = {isSubmitting} > Submit </ BUTTON >
Ahora, el formulario se envía cuando el usuario hace clic en el botón Enviar, mientras se envía el formulario, el botón está inactivo y, una vez que se completa el envío, el formulario se restablece y borra los campos.
En una aplicación de pila completa, el formulario se enviaría a través de una solicitud POST . En aras de ver los datos que envía nuestro formulario en este ejemplo sin base de datos, podemos
alert
los valores cuando el usuario envía el formulario.Agrega un
setTimeout
función que tiene un retraso de 0,5 segundos y contiene un alert
con un JSON.stringify
función que imprime los datos del formulario cuando se envía el formulario.También podemos mover el
resetForm
y setSubmitting
funciones dentro de este setTimeout
para que se llamen después de un retraso de 0,5 segundos: // Simulate submitting to database , shows us values submitted, resets form setTimeout(() => { alert( JSON .stringify( values , null , 2 )); resetForm(); setSubmitting( false ); }, 500 );
Nuestro formulario de contacto ya está completo.
El componente, en su totalidad, se ve así:
import React from 'react' ; import styled from 'styled-components' ; import { Form, Button } from 'react-bootstrap' ; import { Formik, ErrorMessage } from 'formik' ; import * as Yup from 'yup' ; const CONTAINER = styled.div` background : #F7F9FA; height : auto; width : 90 %; margin: 5 em auto; color : snow; -webkit- box -shadow: 5 px 5 px 5 px 0 px rgba( 0 , 0 , 0 , 0.4 ); -moz- box -shadow: 5 px 5 px 5 px 0 px rgba( 0 , 0 , 0 , 0.4 ); box -shadow: 5 px 5 px 5 px 0 px rgba( 0 , 0 , 0 , 0.4 ); @media( min - width : 786 px) { width : 60 %; } label { color : # 24 B9B6; font- size : 1.2 em; font-weight: 400 ; } h1 { color : # 24 B9B6; padding-top: .5 em; } .form-group { margin-bottom: 2.5 em; } .error { border: 2 px solid #FF6565; } .error-message { color : #FF6565; padding: .5 em .2 em; height : 1 em; position: absolute; font- size : .8 em; } `; const MYFORM = styled(Form)` width : 90 %; text -align: left; padding-top: 2 em; padding-bottom: 2 em; @media( min - width : 786 px) { width : 50 %; } `; const BUTTON = styled(Button)` background : # 1863 AB; border: none; font- size : 1.2 em; font-weight: 400 ; &:hover { background : # 1 D3461; } `; // RegEx for phone number validation const phoneRegExp = /^(\+?\d{ 0 , 4 })?\s?-?\s?(\(?\d{ 3 }\)?)\s?-?\s?(\(?\d{ 3 }\)?)\s?-?\s?(\(?\d{ 4 }\)?)?$/ // Schema for yup const validationSchema = Yup.object(). shape ({ name: Yup.string() . min ( 2 , "*Names must have at least 2 characters" ) . max ( 100 , "*Names can't be longer than 100 characters" ) .required( "*Name is required" ), email: Yup.string() .email( "*Must be a valid email address" ) . max ( 100 , "*Email must be less than 100 characters" ) .required( "*Email is required" ), phone: Yup.string() .matches(phoneRegExp, "*Phone number is not valid" ) .required( "*Phone number required" ), blog: Yup.string() .url( "*Must enter URL in http://www.example.com format" ) .required( "*URL required" ) }); const BasicForm = () => { return ( <CONTAINER> //Sets initial values for form inputs <Formik initialValues={{ name: "" , email: "" , phone: "" , blog: "" }} validationSchema={validationSchema} onSubmit={(values, {setSubmitting, resetForm}) => { // When button submits form and form is in the process of submitting, submit button is disabled setSubmitting( true ); // Simulate submitting to database, shows us values submitted, resets form setTimeout(() => { alert(JSON.stringify(values, null , 2 )); resetForm(); setSubmitting( false ); }, 500 ); }} > { /* Callback function containing Formik state and helpers that handle common form actions */ } {( {values, errors, touched, handleChange, handleBlur, handleSubmit, isSubmitting }) => ( <MYFORM onSubmit={handleSubmit} className= "mx-auto" > {console. log (values)} <Form.Group controlId= "formName" > <Form.Label>Name :</Form.Label> <Form.Control type= "text" /* This name property is used to access the value of the form element via values.nameOfElement */ name= "name" placeholder= "Full Name" /* Set onChange to handleChange */ onChange={handleChange} /* Set onBlur to handleBlur */ onBlur={handleBlur} /* Store the value of this input in values.name, make sure this is named the same as the name property on the form element */ value={values.name} /* Check if the name field (this field) has been touched and if there is an error, if so add the .error class styles defined in the CSS (make the input box red) */ className={touched.name && errors.name ? "error" : null } /> { /* Applies the proper error message from validateSchema when the user has clicked the element and there is an error, also applies the .error-message CSS class for styling */ } {touched.name && errors.name ? ( <div className= "error-message" >{errors.name}</div> ): null } </Form.Group> <Form.Group controlId= "formEmail" > <Form.Label>Email :</Form.Label> <Form.Control type= "text" name= "email" placeholder= "Email" onChange={handleChange} onBlur={handleBlur} value={values.email} className={touched.email && errors.email ? "error" : null } /> {touched.email && errors.email ? ( <div className= "error-message" >{errors.email}</div> ): null } </Form.Group> <Form.Group controlId= "formPhone" > <Form.Label>Phone :</Form.Label> <Form.Control type= "text" name= "phone" placeholder= "Phone" onChange={handleChange} onBlur={handleBlur} value={values.phone} className={touched.phone && errors.phone ? "error" : null } /> {touched.phone && errors.phone ? ( <div className= "error-message" >{errors.phone}</div> ): null } </Form.Group> <Form.Group controlId= "formBlog" > <Form.Label>Blog :</Form.Label> <Form.Control type= "text" name= "blog" placeholder= "Blog URL" onChange={handleChange} onBlur={handleBlur} value={values.blog} className={touched.blog && errors.blog ? "error" : null } /> {touched.blog && errors.blog ? ( <div className= "error-message" >{errors.blog}</div> ): null } </Form.Group> <BUTTON variant= "primary" type= "submit" disabled={isSubmitting}> Submit </BUTTON> </MYFORM> )} </Formik> </CONTAINER> ); } export default BasicForm;
Puede ver el formulario en línea aquí o consultar el código en Github Repo para este proyecto.