Gérer ses formulaires avec react-hook-form et yup avec une validation très simple

author
Andréas Hanss · Jan 4, 2022
dev | 2 min
Image descriptive

Qu'est-ce que React Hook Form ?

React Hook Form est l'un des frameworks les plus performants et flexibles pour react et react native pour construire des formulaires. Tandis que yup est l'une des bibliothèques les plus simples et les plus agréables pour valider la structure des données. En combinant les deux, vous obtenez un flux de travail fluide et efficace que je vous suggère fortement d'essayer.

Quelques interrogation me venaient cependant souvent à l'esprit :

  • Pourquoi devrais-je importer yup dans chaque composant où j'ai un formulaire ? En plus du fait que l'auto-importation de yup est assez bancale avec Typescript.
  • Comment puis-je écrire moins de code et profiter de l'inférence de type TypeScript ?

Après avoir remarqué que je copiais à chaque fois le même code, j'ai fini par créer ces deux hooks pour pouvoir concevoir rapidement un formulaire avec sa validation dans une application react.

Créer facilement un formulaire avec React Hook Form et Yup pour la validation

Et après quelques réflexions, voici ces extraits de code qui profitent de l'inférence de type TypeScript pour donner l'auto-complétion et la sécurité de type.

1
import { yupResolver } from '@hookform/resolvers/yup';
2
import { useForm, UseFormProps, UseFormReturn } from 'react-hook-form';
3
import * as Yup from 'yup';
4
5
/**
6
* This function is type inference ready and will auto-validate the useForm with the proper values.
7
*
8
* If you don't already have the schema or use a dynamic schema, consider useFormWithSchemaBuilder()
9
*
10
* @param schema - A valid you schema
11
* @param useFormProps
12
* @returns
13
*/
14
export function useFormWithSchema<T extends Yup.AnyObjectSchema>(
15
schema: T,
16
useFormProps?: UseFormProps<Yup.Asserts<T>>,
17
): UseFormReturn<Yup.Asserts<T>> {
18
return useForm({ ...useFormProps, resolver: yupResolver(schema) });
19
}
20
21
/**
22
* Use this to prevent importing yup library in your components, if you don't already have the schema, and if you want to have a dynamic schema values.
23
* This is rebuild on each render.
24
* This function is type inference ready and will auto-validate the useForm with the proper values.
25
*
26
* If you have already the schema or use a static schema, consider useFormWithSchema()
27
*
28
* @param schemaBuilder - Should return a validation schema
29
* @param useFormProps Do not provide "resolver" value as it will be ignored.
30
* @returns
31
*/
32
export function useFormWithSchemaBuilder<T extends Yup.AnyObjectSchema>(
33
schemaBuilder: (yup: typeof Yup) => T,
34
useFormProps?: UseFormProps<Yup.Asserts<T>>,
35
): UseFormReturn<Yup.Asserts<T>> {
36
return useForm({ ...useFormProps, resolver: yupResolver(schemaBuilder(Yup)) });
37
}

Exemple pratique

Rien de bien compliqué, il suffit simplement de copier le code ci-dessus et essayez de l'utiliser, il a été fait en deux formats différents, chacun ayant son propre but.

Faites attention au fait que vous n'avez pas besoin de passer un resolver aux arguments useform car il sera de toute façon écrasé par l'extrait de code comme vous pouvez le voir.

La vraie valeur ajoutée ici est dans l'inférence de type Typescript qui donne une bonne auto-complétion et la sécurité des types.

En utilisant un schéma yup déjà existant

1
import * as yup from "yup";
2
3
const schema = yup.object({
4
quantity: yup.number().min(props.minQuantityDynamic)
5
})
6
7
const MyComponent: React.FC = () => {
8
const { register } = useFormWithSchema(formSchema);
9
// …
10
}

Ou en utilisant la fonction de construction

Si vous n'avez pas encore de schéma et que vous ne voulez pas importer yup partout, utilisez la fonction d'usinage. De plus, cela permet de jouer avec la validation dynamique.

Cela a un léger coût en termes de performances, car le render est renouvelé à chaque fois, ce qui implique la création d'un nouveau schéma à chaque fois. C'est pourquoi vous pouvez envisager l'autre approche si jamais des problèmes de performances se font sentir.

1
const { register } = useFormWithSchemaBuilder((yup) => yup.object({
2
quantity: yup.number().min(props.minQuantityDynamic)
3
}));