En esta ocasión, volveremos a crear formularios dinámicos pero ahora con ayuda de la librería de react-hook-form.
Nota 📣: Necesitas tener conocimiento en Typescript para seguir este tutorial, así como de React JS.
Tal vez te interese este articulo, donde también hacemos lo mismo que en este publish, pero usando la librería de Formik. 😉
Tabla de contenido.
📌 Creando el objeto de formulario.
📌 Creando el tipado para los inputs.
📌 Ahora si, creamos el objeto de formulario con ayuda del tipado.
📌 Creando el esquema de validaciones para nuestro formulario.
📌 Función para generar los inputs.
📌 Creando el componente de formulario.
📌 Creando los componentes de cada input.
📌 Usando nuestro componente Form.
💊 Tecnologías a utilizar.
- React JS 18.2.0
- TypeScript 4.9.3
- React Hook Kind 7.43.0
- Vite JS 4.1.0
- Tailwind CSS 3.2.4 (no se muestra el proceso de instalación ni de configuración)
💊 Creando el proyecto.
Al proyecto le colocaremos el nombre de: dynamic-forms-rhf
(opcional, tu le puedes poner el nombre que gustes).
npm create vite@newest
Creamos el proyecto con Vite JS y seleccionamos React con TypeScript.
Luego ejecutamos el siguiente comando para navegar al directorio que se acaba de crear.
cd dynamic-forms-rhf
Luego instalamos las dependencias.
npm set up
Después abrimos el proyecto en un editor de código (en mi caso VS code).
code .
💊 Primeros pasos.
Dentro del archivo src/App.tsx borramos todo y creamos un componente que muestre un hola mundo
const App = () => {
return <div>Hey world</div>;
};
export default App;
🚨 Nota: Cada vez que creamos una nueva carpeta, también crearemos un archivo index.ts para agrupar y exportar todas las funciones y componentes de otros archivos que están dentro de la misma carpeta, y que dichas funciones puedan ser importadas a traves de una sola referencia a esto se le conoce como archivo barril.
Vamos a crear un format, creamos una carpeta src/elements y dentro creamos un archivo Structure.tsx.
export const Structure = ({ kids }: JSX.Ingredient[] ) => {
return (
<>
<h1 className='text-center my-10 text-5xl'>
<span>Dynamic Kind</span>
<span className='font-bold bg-clip-text text-transparent text-[#EC5990]'>
{' - '}
React Hook Kind
</span>
</h1>
<primary className='grid sm:grid-cols-2 grid-cols-1 sm:mb-0 mb-10 gap-10 place-items-start justify-items-center px-5'>
{kids}
</primary>
</>
)
}
Ahora, dentro de archivo src/App.tsx, agregamos el format.
import { Structure } from './elements'
const App = () => {
return (
<Structure>
<span>Kind</span>
</Structure>
)
}
export default App
Luego vamos a instalar los paquetes necesarios.
- react-hook-form, para manejar los formularios de una manera mas fácil.
- yup, para manejar validaciones en los formularios.
- @hookform/resolvers, para integrar yup con react-hook kind.
npm set up -E react-hook-form @hookform/resolvers yup
Anteriormente ya había realizado este mismo ejercicio de formularios dinámicos pero usando la librería de Formik, y la verdad es muy comparable lo que vamos a realizar, lo único que cambiar son los componentes como el formulario e inputs.
💊 Creando el objeto de formulario.
💊 Creando el tipado para los inputs.
Antes, vamos a crear el tipado. Creamos una nueva carpeta src/varieties y creamos el archivo index.ts.
Ahora primero creamos la interfaz para los inputs, el cual puede incluso tener más propiedades, pero estas son suficientes para hacer este ejemplo.
Lo mas destacado son las ultimas tres propiedades de la interfaz InputProps:
- typeValue: necesaria ya que necesitamos indicarle a Yup que tipo de valor acepta el enter.
-
validations: validaciones que se le establecerán a Yup en base al enter; solo coloque validaciones básicas, aunque puedes integrar más si buscas en la documentación de Yup.
- La validación que tal vez se mas se te complique puede ser oneOf, si no haz usado Yup. Esta validación, necesita de una referencia o sea el identify de otro enter para validar si ambos enter contienen el mismo contenido. Un ejemplo de donde usar esta validación es en un enter donde creas un password y otro donde tienes que repetir password y ambos valores tienen que coincidir.
- choices: esta propiedad es necesario solo si el enter es un choose o un grupo de inputs de tipo radio
export interface InputProps boolean
placeholder?: string
label?: string
typeValue?: 'boolean'
export interface Choose quantity
desc: string
export interface Validation 'oneOf'
worth?: string
También de una vez creamos este tipo para los tipos de formularios que vamos a desarrollar.
En este caso solo vamos a crear dos formularios.
export sort FormSection = 'register' | 'one other'
💊 Ahora si, creamos el objeto de formulario con ayuda del tipado.
Gracias a Typescript podemos crear nuestros formularios en este objeto.
Creamos una nueva carpeta src/lib y dentro creamos el archivo kind.ts y agregamos lo siguiente:
import { FormSection, InputProps } from '../varieties';
export const types: { [K in FormSection]: InputProps[] } =
{
register: [
{
label: "New username",
type: "text",
name: "username",
placeholder: "New username",
value: "",
validations: [
{
type: "minLength",
value: 3,
message: "Min. 3 characters",
},
{
type: "required",
message: "Username is required"
},
],
},
{
label: "New Password",
sort: "password",
identify: "password",
placeholder: "New password",
worth: "",
validations: [
{
type: "required",
message: "Password is required"
},
{
type: "minLength",
value: 5,
message: "Min. 5 characters",
}
],
},
{
label: 'Repeat your password',
sort: "password",
identify: "repeat_password",
placeholder: "Repeat password",
worth: "",
validations: [
{
type: "required",
message: "Repeat password is required"
},
{
type: "minLength",
value: 5,
message: "Min. 5 characters",
},
{
type: 'oneOf',
message: 'Passwords must match',
ref: 'password'
}
],
},
],
one other: [
{
label: "E-mail address",
type: "email",
name: "email",
placeholder: "correo@correo.com",
value: "",
validations: [
{
type: "required",
message: "Email is required"
},
{
type: "isEmail",
message: "Email no valid"
}
],
},
{
sort: "choose",
identify: "rol",
label: "Choose an choice: ",
worth: "",
choices: [
{
value: "admin",
desc: "Admin",
},
{
value: "user",
desc: "User"
},
{
value: "super-admin",
desc: "Super Admin"
}
],
validations: [
{
type: "required",
message: "Rol is required"
}
]
},
{
sort: "radio",
identify: "gender",
label: "Gender: ",
worth: "",
choices: [
{
value: 'man',
desc: "Man"
},
{
value: "woman",
desc: "Woman"
},
{
value: "other",
desc: "Other"
},
],
validations: [
{
type: "required",
message: "Gender is required"
}
]
},
{
sort: "checkbox",
identify: "phrases",
typeValue: "boolean",
label: "Phrases and Circumstances",
worth: false,
validations: [
{
type: "isTrue",
message: "Accept the terms!"
}
]
},
]
}
💊 Creando el esquema de validaciones para nuestro formulario.
Vamos a crear un nuevo archivo en src/lib y lo nombramos getInputs.ts
Creamos una nueva función para generar las validaciones a cada enter.
Esta función recibe los campos, y cada campo es de tipo InputProps. También vamos a crear 2 tipos solamente para que Typescript no nos moleste mas adelante.
Nota que creamos los tipos YupBoolean y YupString. Si quieres puedes agregar otros tipos ya sea para manejar algún otro tipo de dato como el numérico o el arreglo. Por ejemplo:
sort YupNumber = Yup.NumberSchema<boolean | undefined, AnyObject, quantity | undefined>
Yo no lo agrego, porque en mis interfaces no manejo alguna validación de tipo numero o arreglo.
import * as Yup from "yup";
import { AnyObject } from "yup/lib/varieties";
import { FormSection, InputProps } from '../varieties';
import { types } from '../lib';
sort YupBoolean = Yup.BooleanSchema<boolean | undefined, AnyObject, boolean | undefined>
sort YupString = Yup.StringSchema<string | undefined, AnyObject, string | undefined>
const generateValidations = (area: InputProps) => {}
Primero creamos una variable que se inicializara con el tipo de dato que manejara nuestro enter. El tipo de dato lo obtenemos de la propiedad typeValue, en caso de que sea undefined por defecto el tipo de dat sera string, y entonces ejecutamos la función
let schema = Yup[field.typeValue || 'string']()
Luego vamos a recorrer las validaciones del campo, ya que es un arreglo.
Dentro del ciclo, usaremos un swap case, evaluando que tipo de regla es la que tiene dicho campo.
const generateValidations = (area: InputProps) => {
let schema = Yup[field.typeValue || 'string']()
for (const rule of area.validations) {
swap (rule.sort) { }
}
}
En cada caso del swap vamos a sobrescribir la variable schema. De la siguiente manera:
Si tiene una validación ‘isTrue’ significa que el enter maneja valores booleanos, por lo cual queremos que nuestro schema se comporte como un YupBoolean, ya que si no Typescript se estaría quejando. Luego ejecutamos la función que tenga que ver con cada caso.
Por ejemplo, en el caso de ‘isTrue’, ejecutamos la función que se llama exactamente igual, y dentro le pasamos el mensaje
case 'isTrue' : schema = (schema as YupBoolean).isTrue(rule.message); break;
En el caso de que la validación sea oneOf, necesitamos enviarle, como primer parámetro un arreglo y como segundo parámetro un mensaje.
En el caso del arreglo, debe ser el valor con el que quieres que coincida, pero en este caso queremos que coincida con el valor de otro campo, por eso usamos Yup.ref el cual necesita un string que hace referencia al atributo identify de un enter.
Para que asi cuando se haga la validación, se verifique si ambos campos contienen el mismo valor.
case 'oneOf' : schema = (schema as YupString)
.oneOf(
[ Yup.ref(rule.ref as string) ],
rule.message
);
break;
Asi quedaría nuestra primera función. Al ultimate retornamos la variable schema.
Nota que al inicio de la función, colocamos una condición donde si el campo no tiene validaciones entonces retornar null y evitar ejecutar el ciclo.
import * as Yup from "yup";
import { AnyObject } from "yup/lib/varieties";
import { FormSection, InputProps } from '../varieties';
import { types } from '../lib';
sort YupBoolean = Yup.BooleanSchema<boolean | undefined, AnyObject, boolean | undefined>
sort YupString = Yup.StringSchema<string | undefined, AnyObject, string | undefined>
const generateValidations = (area: InputProps) => {
if (!area.validations) return null
let schema = Yup[field.typeValue || 'string']()
for (const rule of area.validations) {
swap (rule.sort) {
case 'isTrue' : schema = (schema as YupBoolean).isTrue(rule.message); break;
case 'isEmail' : schema = (schema as YupString).e mail(rule.message); break;
case 'minLength': schema = (schema as YupString).min(rule?.worth as quantity, rule.message); break;
case 'oneOf' : schema = (schema as YupString).oneOf([Yup.ref((rule as any).ref)], rule.message); break;
default : schema = schema.required(rule.message); break;
}
}
return schema
}
💊 Función para generar los inputs.
Primero vamos a crear un función y la nombramos getInputs, la cual es de tipo genérico y recibe como parámetro la part (o sea que formulario quieres obtener sus campos, en este caso puede ser el formulario de signUp o el otro).
Vamos a crear dos variables que las inicializaremos como objetos vacíos y que al ultimate deberán contener nuevas propiedades.
export const getInputs = <T>(part: FormSection) => {
let initialValues: { [key: string]: any } = {};
let validationsFields: { [key: string]: any } = {};
};
Dentro de la función haremos un ciclo for of. En el caul vamos a recorrer los campos de un formulario en especifico.
-
Dentro del ciclo, vamos a computar los valores en la variable de initialValues, y para computar los valores usamos la propiedad identify del campo.
-
Verificamos si existen validaciones para el campo.
- Si no hay validaciones, entonces seguir con el siguiente campo.
- Si hat validaciones, ejecutamos la función que creamos anteriormente generateValidations mandando el campo como argumento.
-
Luego a la variable validationsFields, también le computamos los valores usando la propiedad identify del campo, y le asignamos el schema de validación que se ha generado.
for (const area of types[section]) {
initialValues[field.name] = area.worth;
if (!area.validations) proceed;
const schema = generateValidations(area)
validationsFields[field.name] = schema;
}
Una vez terminado el ciclo, debemos retornar 3 propiedades.
- El esquema de validación dentro de un Yup.object, esparciendo las propiedades de validationsFields.
validationSchema: Yup.object({ ...validationsFields }),
- Los valores iniciales, y haremos que se comporten como genérico para poder usarlos después
initialValues: initialValues as T,
– Los campos que queremos mostrar en nuestro formulario.
inputs: types[section]
Asi se vería al ultimate nuestra función
export const getInputs = <T>(part: FormSection) => {
let initialValues: { [key: string]: any } = {};
let validationsFields: { [key: string]: any } = {};
for (const area of types[section]) {
initialValues[field.name] = area.worth;
if (!area.validations) proceed;
const schema = generateValidations(area)
validationsFields[field.name] = schema;
}
return {
validationSchema: Yup.object({ ...validationsFields }),
initialValues: initialValues as T,
inputs: types[section],
};
};
💊 Creando el componente de formulario.
Primero vamos a preparar la interfaz para las props que va a recibir nuestro componente Kind.
- onSubmit, función que ejecuta el formulario.
- labelButtonSubmit, texto que mostrara el botón.
- titleForm, texto que mostrara el formulario.
Los ultimas 3 propiedades son lo que regresa la función que hicimos para generar los inputs y sus validaciones.
interface Props {
onSubmit: (information: unknown) => void
labelButtonSubmit?: string
titleForm?: string
initialValues: unknown
validationSchema: SchemaForm
inputs: InputProps[]
}
La propiedad validationSchema es de tipo SchemaForm.
// src/varieties/index.ts
export sort SchemaForm = OptionalObjectSchema<{
[x: string]: any;
}, AnyObject, TypeOfShape<{
[x: string]: any;
}>>
Ahora creamos el componente, y dentro desestructuramos las props que recibe el componente.
Luego usamos el hook de useForm, el cual vamos a establecer un objeto como argumento, accedemos a la propiedad:
- resolver, para establecer el esquema de validación, para ello usamos la función yupResolver y le pasamos como argumento el validationSchema que viene por props.
- defaultValues, para establecer los valores por defecto y le asignaremos la props de initialValues.
Toma en cuenta que no desestructuramos nada del hook useForm.
import { yupResolver } from '@hookform/resolvers/yup'
import { useForm } from 'react-hook-form'
export const Kind = ({ ...props }: Props) => {
const {
initialValues,
inputs,
onSubmit,
validationSchema,
titleForm,
labelButtonSubmit = 'Submit'
} = props
const formMethods = useForm({
resolver: yupResolver(validationSchema),
defaultValues: { ...(initialValues as any) }
})
return (
<></>
)
}
Después, vamos a usar un componente que nos ofrece react-hook-form, que es el FormProvider y le vamos a esparcir los formMethods del hook useForm.
El FormProvider nos ayudara a comunicar el estado del formulario con los componentes (inputs) que estén anidados dentro del FormProvider. Con el propósito de separar los componentes y no tener todo en un mismo archivo.
Dentro del FormProvider colocaremos un kind y en el método onSubmit de la etiqueta kind, vamos a ejecutar una propiedad del formMethods, que es el handleSubmit, y como argumento le pasamos el onSubmit que recibe el componente Kind por props.
Este handleSubmit, solo se va a ejecutar si no hay errores en cada enter, y cuando se ejecute nos devolverá los valores de cada enter.
import { FormProvider, useForm } from 'react-hook-form'
// interface
export const Kind = ({ ...props }: Props) => {
// props
const formMethods = useForm({
resolver: yupResolver(validationSchema),
defaultValues: { ...(initialValues as any) }
})
return (
<FormProvider {...formMethods}>
<kind
onSubmit={formMethods.handleSubmit(onSubmit)}
className='bg-secondary rounded-md p-10 pt-5 shadow-2xl shadow-primary/30 flex flex-col gap-2 border border-primary w-full min-h-[390px]'
>
<part className='flex-1 flex flex-col gap-3'>
{/* inputs right here */}
</part>
</kind>
</FormProvider>
)
}
Ahora vamos a crear una función, para retornar los diferentes tipos de inputs.
Usamos la prop inputs que desestructuramos de las props que recibe el componente Kind.
En base al tipo de enter vamos a renderizar un uno u otro enter.
Nota que estamos usando componentes que aun no hemos creado. También nota, que de las propiedades de cada enter, vamos a excluir las validations, typeValue y worth, porque son valores que no necesita nuestro enter directamente.
Una cosa a mejorar sobre esta función, es que puedes crear un componente aparte, y crear un diccionario con los componentes y el tipo de enter.
En este caso no lo hago, para no extenderme más.
const createInputs = () =>
inputs.map(({ validations, typeValue, worth, ...inputProps }) => {
swap (inputProps.sort) {
case 'choose':
return <CustomSelect {...inputProps} key={inputProps.identify} />
case 'checkbox':
return <CustomCheckbox {...inputProps} key={inputProps.identify} />
case 'radio':
return <CustomRadio {...inputProps} key={inputProps.identify} />
default:
return <CustomInput {...inputProps} key={inputProps.identify} />
}
})
Finalmente, ejecutamos la función createInputs dentro de la etiqueta part. E inmediatamente vamos a crear los customized inputs.
// imports
// interface
export const Kind = ({ ...props }: Props) => {
// props
const formMethods = useForm({
resolver: yupResolver(validationSchema),
defaultValues: { ...(initialValues as any) }
})
const createInputs = () =>
inputs.map(({ validations, typeValue, worth, ...inputProps }) => {
swap (inputProps.sort) {
case 'choose':
return <CustomSelect {...inputProps} key={inputProps.identify} />
case 'checkbox':
return <CustomCheckbox {...inputProps} key={inputProps.identify} />
case 'radio':
return <CustomRadio {...inputProps} key={inputProps.identify} />
default:
return <CustomInput {...inputProps} key={inputProps.identify} />
}
})
return (
<FormProvider {...formMethods}>
<kind
onSubmit={formMethods.handleSubmit(onSubmit)}
className='bg-secondary rounded-md p-10 pt-5 shadow-2xl shadow-primary/30 flex flex-col gap-2 border border-primary w-full min-h-[390px]'
>
<part className='flex-1 flex flex-col gap-3'>
{ createInputs() }
</part>
</kind>
</FormProvider>
)
}
💊 Creando los componentes de cada enter.
Primero, vamos a crear un mensaje de error, que se va a mostrar cada que la validación del enter falle.
Dentro de src/elements creamos ErrorMessage.tsx
interface Props { error?: string }
export const ErrorMessage = ({ error }: Props) => {
if (!error) return null
return (
<div className='w-full grid place-content-end'>
<p className='text-red-400 text-sm'>{error}</p>
</div>
)
}
Ahora, vamos a crear una nueva carpeta src/elements/inputs y dentro crearemos 4 archivos.
Estos cuatro componentes que vamos a crear reciben props que son de tipo CustomInputProps. Puedes colocarlo en el archivo src/varieties/index.ts
export sort CustomInputProps = Omit<InputProps, 'validations' | 'typeValue' | 'worth'>
Y ademas como cada enter que crearemos estará dentro de un FormProvider, podemos utilizar otro customized hook de react-hook-form, el cual es useFormContext, este hook nos ayudara a conectar el estado del formulario con el enter.
- CustomGenericInput.tsx
De useFormContext, obtenemos el la propiedad register, y la propiedad errors dentro del formState.
const {
register,
formState: { errors }
} = useFormContext()
Creamos el error, computando el objeto de errors con la prop identify que recibe el componente y obtenemos el mensaje.
const error = errors[name]?.message as string | undefined
Al momento de construir el enter, necesitamos esparcir las propiedades de la función register, el cual tenemos que pasar le la prop identify para que react-hook-form identifique que errores y validaciones debe tener este enter.
Luego le esparcimos las demás propiedades en caso de que tenga más (como por ejemplo el placeholder).
<enter
className='py-1 px-2 rounded w-full text-black'
{...register(identify)}
{...props}
id={id}
/>
Asi quedaría al ultimate este componente.
import { useFormContext } from 'react-hook-form'
import { ErrorMessage } from '../../elements'
import { CustomInputProps } from '../../varieties'
export const CustomInput = ({ identify, label, ...props }: CustomInputProps) => {
const {
register,
formState: { errors }
} = useFormContext()
const error = errors[name]?.message as string | undefined
const id = `${identify}-${props.sort}-${label}`
return (
<div className='w-full flex gap-1 flex-col'>
{label && (
<label className='text-white text-sm' htmlFor={id}>
{label}
</label>
)}
<enter
className='py-1 px-2 rounded w-full text-black'
{...register(identify)}
{...props}
id={id}
/>
<ErrorMessage error={error} />
</div>
)
}
- CustomCheckbox.tsx
import { useFormContext } from 'react-hook-form'
import { ErrorMessage } from '../../elements'
import { CustomInputProps } from '../../varieties'
export const CustomCheckbox = ({ identify, label, ...props }: CustomInputProps) => {
const {
register,
formState: { errors }
} = useFormContext()
const error = errors[name]?.message as string | undefined
return (
<div>
<label className='flex gap-2 items-center cursor-pointer w-fit'>
<enter {...props} {...register(identify)} />
{label}
</label>
<ErrorMessage error={error} />
</div>
)
}
- CustomSelect.tsx
Este enter es casi igual que todos los demás, solo que aquí tenemos la prop choices donde vendrán los valores del choose que se pueden seleccionar.
import { useFormContext } from 'react-hook-form'
import { ErrorMessage } from '../../elements'
import { CustomInputProps } from '../../varieties'
export const CustomSelect = ({ identify, label, choices, ...props }: CustomInputProps) => {
const {
register,
formState: { errors }
} = useFormContext()
const error = errors[name]?.message as string | undefined
const id = `${identify}-${props.sort}-${label}`
return (
<div className='flex flex-col gap-2'>
<div className='flex items-center gap-4'>
<label htmlFor={id}>{label}</label>
<choose {...register(identify)} {...props} id={id} className='p-2 rounded flex-1 text-black'>
<choice worth=''>--- Choose choice ---</choice>
{choices &&
choices.map(({ desc, worth }) => (
<choice key={worth} worth={worth}>
{desc}
</choice>
))}
</choose>
</div>
<ErrorMessage error={error} />
</div>
)
}
- CustomRadioGroup
Muy parecido al CustomSelect.tsx. Solo que aquí renderizamos un enter de tipo radio.
import { useFormContext } from 'react-hook-form'
import { ErrorMessage } from '../../elements'
import { CustomInputProps } from '../../varieties'
export const CustomRadio = ({ identify, label, choices, ...props }: CustomInputProps) => {
const {
register,
formState: { errors }
} = useFormContext()
const error = errors[name]?.message as string | undefined
return (
<div className='flex flex-col'>
<div className='flex items-center gap-4'>
<label>{label}</label>
<part className='flex justify-between flex-1'>
{choices &&
choices.map(({ desc, worth }) => (
<label
key={worth}
className='flex items-center gap-1 cursor-pointer hover:underline rounded p-1'
>
<enter {...register(identify)} {...props} worth={worth} sort='radio' />
{desc}
</label>
))}
</part>
</div>
<ErrorMessage error={error} />
</div>
)
}
💊 Usando nuestro componente Kind.
Ahora vamos al archivo src/App.tsx
Para usar el componente Kind.
Tenemos que ejecutar la función getInputs y obtener las validaciones, valores iniciales e inputs. Lo haremos fuera del componente. También creamos una interfaz para que los valores iniciales se comporten como dicha interfaz.
interface SignUpFormType {
username: string
password: string
repeat_password: string
}
const signUpForm = getInputs<SignUpFormType>('register')
Luego importamos el componente Kind, le esparcimos las propiedades que nos regresa getInput. Y también le pasamos las demás props.
import { Structure, Kind } from './elements'
import { getInputs } from './lib'
interface SignUpFormType {
username: string
password: string
repeat_password: string
}
const signUpForm = getInputs<SignUpFormType>('register')
const App = () => {
const onSubmitSignUp = (information: unknown) => console.log({ singUp: information })
return (
<Structure>
<Kind
{...signUpForm}
onSubmit={onSubmitSignUp}
titleForm='Signal Up!'
labelButtonSubmit='Create account'
/>
</Structure>
)
}
export default App
En el caso de que quieras sobrescribir los valores iniciales, solamente te creas una nueva constante esparciendo los valores iniciales y luego sobrescribiendo lo que necesites. Para luego pasar le un nuevo valor a la prop de initialValues.
const App = () => {
const onSubmitSignUp = (information: unknown) => console.log({ singUp: information })
const initialValuesSignUp: SignUpFormType = {
...signUpForm.initialValues,
username: '@franklin361'
}
return (
<Structure>
<Kind
{...signUpForm}
initialValues={initialValuesSignUp}
onSubmit={onSubmitSignUp}
titleForm='Signal Up!'
labelButtonSubmit='Create account'
/>
</Structure>
)
}
export default App
Y asi mismo puedes incluir varios formularios de manera dinámica.
import { Structure, Kind } from './elements'
import { getInputs } from './lib'
interface SignUpFormType {
username: string
password: string
repeat_password: string
}
interface AnotherFormType {}
const signUpForm = getInputs<SignUpFormType>('register')
const anotherForm = getInputs<AnotherFormType>('one other')
const App = () => {
const onSubmitSignUp = (information: unknown) => console.log({ singUp: information })
const onSubmitAnotherForm = (information: unknown) => console.log({ one other: information })
const initialValuesSignUp: SignUpFormType = {
...signUpForm.initialValues,
username: '@franklin361'
}
return (
<Structure>
<Kind
{...signUpForm}
initialValues={initialValuesSignUp}
titleForm='Signal Up!'
onSubmit={onSubmitSignUp}
labelButtonSubmit='Create account'
/>
<Kind
{...anotherForm}
titleForm='One other kind!'
onSubmit={onSubmitAnotherForm}
labelButtonSubmit='Ship data'
/>
</Structure>
)
}
export default App
💊 Conclusión.
React Hook Kind es una de mis librearas favoritas, ya que tiene ciertas ventajas sobre otras librerías populares como por ejemplo Formik; como por ejemplo el bundle dimension es mas pequeño, tiene menos dependencias, produce menos re-renders, and many others. 😉
Pero de igual manera ambas son librerías muy usadas.
Espero que te haya gustado esta publicación y que también espero haberte ayudado a entender como realizar formularios dinámicos usando React Hook Kind. 🙌
Si conoces alguna otra forma distinta o mejor de realizar esta aplicación con gusto puedes comentarla.
Te invito a que revises mi portafolio en caso de que estés interesado en contactarme para algún proyecto! Franklin Martinez Lucas
🔵 No olvides seguirme también en twitter: @Frankomtz361
💊 Demostración easy.
https://dynamic-form-rhf.netlify.app/
💊 Código fuente.