Gérer les formulaires dans React peut rapidement devenir complexe, surtout avec plusieurs champs, des règles de validation, et la gestion de l'état du formulaire. Dans ce tutoriel, nous allons explorer comment React Hook Form simplifie la gestion des formulaires. Nous commencerons par un formulaire simple d'enregistrement d'utilisateur et l'améliorerons progressivement avec React Hook Form, en décomposant chaque étape pour rester clair et pratique.
Pourquoi la gestion des formulaire est compliquée ?
Les formulaires sont essentiels pour l'interaction utilisateur, mais gérer leur état et validation dans React peut être difficile. Il est souvent nécessaire d'écrire beaucoup de code pour gérer les événements onChange, onSubmit, et la logique de validation.
C'est ici qu'intervient React Hook Form. Cette bibliothèque fournit un ensemble de hooks pour gérer l'état et la validation des formulaires avec un minimum de code. Voici ses avantages :
- Léger : Réduit le code.
- Performances optimisées : Minimise les re-rendus pour de meilleures performances.
- Extensible : S'intègre facilement avec des bibliothèques d'interface utilisateur ou des validations personnalisées.
- API simple : Intuitive et facile à utiliser, même pour les débutants.
Configuration du projet
D'abord, configurons une application React de base et installons React Hook Form.
1# Initialiser un projet React
2npx create-react-app guideco-form
3cd guideco-form
Création d'un formulaire simple sans React Hook Form
Créons un simple formulair sans React Hook Form pour mettre en évidence les limites.
1import React, { useState } from 'react'
2
3const ConnectionForm = () => {
4 const [formData, setFormData] = useState({email: "", password: "" });
5
6 const handleChange = (e) => {
7 const { name, value } = e.target;
8 setFormData({ ...formData, [name]: value });
9 };
10
11 const handleSubmit = (e) => {
12 e.preventDefault();
13 console.log(formData);
14 };
15
16 return (
17 <div className="flex items-center justify-center">
18 <form className="bg-white p-6 rounded shadow-md w-96" onSubmit={handleSubmit}>
19 <label className="block mb-2">
20 Email:
21 <input
22 type="email"
23 name="email"
24 value={formData.email}
25 onChange={handleChange}
26 className="w-full mt-1 p-2 border rounded"
27 />
28 </label>
29
30 <label className="block mb-4">
31 Password:
32 <input
33 type="password"
34 name="password"
35 autoComplete='on'
36 value={formData.password}
37 onChange={handleChange}
38 className="w-full mt-1 p-2 border rounded"
39 />
40 </label>
41
42 <button
43 type="submit"
44 className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
45 >
46 Register
47 </button>
48 </form>
49 </div>
50 );
51}
52
53export default ConnectionForm

Dans le code ci-dessus, nous n'avons que 02 champs de saisie, email et password ainsi qu'un bouton de soumission.
Ces champs sont reliés à un gestionnaire (handleChange) afin de pouvoir mettre à jour le state (formData) en fonction de la saisie de l'utilisateur.
La méthode handleSubmit permet d'afficher les données saisies dans le formulaire dans la console.
Ce code, tant bien qu'éfficace deviendra compliqué au fur et à mesure que nous ajouterons des champs, et des validations telles que la validation des champs obligatoires, la validation de la longueur minimale, la validation du mot de passe, la validation du champ e-mail et afficher les messages d'erreur correspondants.
Par exemple, imaginons que nous voulons un champ pour le numéro de téléphone, un champs pour l'adresse et également certaines vérification avant la soumission de notre formulaire. la fonction handleSubmite deviendrait vite difficile à maintenir :
1const [formData, setFormData] = useState({
2 name: "",
3 email: "",
4 password: "",
5 phone: "",
6 address: ""
7});
8
9const handleSubmit = (e) => {
10 e.preventDefault();
11 let hasError = false;
12
13 // Validations des champs
14 if (!formData.email) {
15 alert("Email is required");
16 hasError = true;
17 } else if (!/\S+@\S+\.\S+/.test(formData.email)) {
18 alert("Invalid email format");
19 hasError = true;
20 }
21
22 if (!formData.password) {
23 alert("Password is required");
24 hasError = true;
25 } else if (formData.password.length < 8) {
26 alert("Password must be at least 8 characters long");
27 hasError = true;
28 }
29
30 if (!formData.phone) {
31 alert("Phone number is required");
32 hasError = true;
33 } else if (!/^\d{10}$/.test(formData.phone)) {
34 alert("Phone number must be 9 digits");
35 hasError = true;
36 }
37
38 if (!formData.address) {
39 alert("Address is required");
40 hasError = true;
41 } else if (formData.address.length < 5) {
42 alert("Address must be at least 5 characters long");
43 hasError = true;
44 }
45
46 if (!hasError) {
47 console.log("Form submitted successfully!", formData);
48 }
49};
50
Introduction à React Hook Form
Voyons maintenant comment React Hook Form peut simplifier cela. Nous allons refactoriser le formulaire précédent en utilisant le hook useForm.
Installons tout d'abord la librairie react-hook-form :
1# Installation de React Hook Form
2npm install react-hook-form
react-hook-form met à notre disposition divers methodes pour la gestion des formulaires dont useForm qui fera l'objet de notre attention.
Importons le hook useForm dans notre code comme suit:
1import { useForm } from "react-hook-form";
Simple formulaire avec react-hook-form
Refactorisons le code précédent afin de gérer l'état de notre formulaire avec react-hook-form
1import React from 'react';
2import { useForm } from "react-hook-form";
3
4const ConnectionForm = () => {
5 const {
6 register,
7 handleSubmit,
8 formState: { errors },
9 } = useForm();
10
11 const onSubmit = (data) => {
12 console.log(data); // Log the submitted data
13 };
14
15
16
17 return (
18 <div className="flex items-center justify-center">
19 <form
20 className="bg-white p-6 rounded shadow-md w-96"
21 onSubmit={handleSubmit(onSubmit)}
22 >
23
24 {/* Email Field */}
25 <label className="block mb-2">
26 Email:
27 <input
28 type="email"
29 {...register("email", { required: "Email is required" })}
30 className="w-full mt-1 p-2 border rounded"
31 />
32 </label>
33
34 {/* Password Field */}
35 <label className="block mb-4">
36 Password:
37 <input
38 type="password"
39 {...register("password", { required: "Password is required" })}
40 className="w-full mt-1 p-2 border rounded"
41 autoComplete='on'
42 />
43 </label>
44
45 <button
46 type="submit"
47 className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
48 >
49 Register
50 </button>
51 </form>
52 </div>
53 );
54}
55
56export default ConnectionForm
creusons un peu plus dans le code ci-haut :
- register: c'est une fonction fournie par le hook useForm. Nous pouvons l'assigner à chaque champ de saisie afin que le react-hook-form puisse suivre les changements de la valeur du champ de saisie :
1<input
2 type="text"
3 className="w-full mt-1 p-2 border rounded"
4 {...register("name", { required: "Name is required" })}
5/>
- handleSubmit : est une fonction que nous pouvons appeler lors afin de gerer la soumission du formulaire.
- errors : est une propriété imbriquée dans l'objet formState qui contiendra les erreurs de validation, s'il y en a.
Ajout de la validation :
Ajoutons maintenant la validation des champs obligatoires et de la longueur minimale aux champs de saisie.
Pour ce faire, nous pouvons passer un objet à la fonction register en tant que second paramètre, comme ceci :
1// ...
2<input
3 type="text"
4 className="w-full mt-1 p-2 border rounded"
5 {...register("name", { required: "Name is required" })}
6/>
7
8// ...
9<input
10 type="email"
11 {...register("email", { required: true, maxLength: 6 })}
12 className="w-full mt-1 p-2 border rounded"
13/>
Le code complet ressemble à ceci :
1import React from 'react';
2import { useForm } from "react-hook-form";
3
4const ConnectionForm = () => {
5 const {
6 register,
7 handleSubmit,
8 formState: { errors },
9 } = useForm();
10
11 const onSubmit = (data) => {
12 console.log(data);
13 };
14
15
16 return (
17 <div className="flex items-center justify-center">
18 <form
19 className="bg-white p-6 rounded shadow-md w-96"
20 onSubmit={handleSubmit(onSubmit)}
21 >
22
23 {/* Email Field */}
24 <label className="block mb-2">
25 Email:
26 <input
27 type="email"
28 {...register("email", {
29 required: true,
30 pattern: /^[^@ ]+@[^@ ]+\.[^@ .]{2,}$/
31 })}
32 className="w-full mt-1 p-2 border rounded"
33 />
34 {errors.email && errors.email.type === "required" && (
35 <p className="text-red-500">Email is required.</p>
36 )}
37 {errors.email && errors.email.type === "pattern" && (
38 <p className="text-red-500">Email is not valid.</p>
39 )}
40 </label>
41
42 {/* Password Field */}
43 <label className="block mb-4">
44 Password:
45 <input
46 type="password"
47 {...register("password", {
48 required: true,
49 minLength: 6
50 })}
51 className="w-full mt-1 p-2 border rounded"
52 autoComplete='on'
53 />
54 {errors.password && errors.password.type === "required" && (
55 <p className="text-red-500">Password is required.</p>
56 )}
57 {errors.password && errors.password.type === "minLength" && (
58 <p className="text-red-500">
59 Password should be at-least 6 characters.
60 </p>
61 )}
62 </label>
63
64 <button
65 type="submit"
66 className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
67 >
68 Register
69 </button>
70 </form>
71 </div>
72 );
73}
74
75export default ConnectionForm

Dans le code ci-haut, nous avons changé la validation de l'email et du mot de passe:
1{...register("email", {
2 required: "Email is required.",
3 pattern: {
4 value: /^[^@ ]+@[^@ ]+\.[^@ .]{2,}$/,
5 message: "Email is not valid."
6 }
7})}
nous avons directement fourni le message d'erreur que nous voulons afficher lors de l'ajout de la validation elle-même.
ous affichons le message d'erreur en utilisant la propriété message disponible dans l'objet errors pour chaque champ de saisie comme ceci :
1{errors.password && errors.password.type === "required" && (
2 <p className="text-red-500">Password is required.</p>
3)}
4{errors.password && errors.password.type === "minLength" && (
5 <p className="text-red-500">
6 Password should be at-least 6 characters.
7 </p>
8)}
Conclusion
En intégrant react-hook-form étape par étape, nous avons réduit le code standard, ajouté une validation puissante et rendu notre formulaire beaucoup plus facile à mettre à l'échelle. Essayez-le dans vos projets et voyez combien de temps vous gagnerez !