Chapitre 16 — Navigation avec React Router
Les formulaires sont partout : inscription, connexion, ajout de produit, recherche… En React, un formulaire bien géré repose sur 3 piliers : champs contrôlés , state structuré et validation . Ce chapitre vous montre une méthode claire et réutilisable, adaptée aux débutants.
Plan du chapitre
- 1) Rappels : champ contrôlé
- 2) Gérer plusieurs champs : 2 stratégies
- 3) Stratégie recommandée : un seul objet form
- 4) Un handleChange générique
- 5) Soumission : onSubmit + preventDefault
- 6) Validations simples (débutant)
- 7) Afficher les erreurs proprement
- 8) Réinitialiser le formulaire
- 9) Bonus : checkbox et select
- 10) Résumé (à retenir)
- 11) Exercice pratique
1) Rappels : champ contrôlé
Un champ contrôlé signifie : la valeur du champ vient du state.
Chaque frappe déclenche onChange, qui met à jour le state.
import { useState } from "react";
export default function App() {
const [name, setName] = useState("");
return (
<label>
Prénom :
<input value={name} onChange={(e) => setName(e.target.value)} />
</label>
);
}
2) Gérer plusieurs champs : 2 stratégies
Quand vous avez 2, 3, 10 champs… vous avez deux approches :
A) Un state par champ
- Facile à comprendre
- Devient vite long quand il y a beaucoup de champs
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
B) Un seul state objet (recommandé)
- Plus propre et scalable
- Permet un
handleChangegénérique
const [form, setForm] = useState({ email: "", password: "" });
3) Stratégie recommandée : un seul objet form
On regroupe tous les champs dans un objet. L’important : ne jamais modifier l’objet directement, on crée une copie (immutabilité).
import { useState } from "react";
export default function App() {
const [form, setForm] = useState({
firstname: "",
email: "",
city: ""
});
return (
<div>
<p>Prénom : {form.firstname}</p>
<p>Email : {form.email}</p>
<p>Ville : {form.city}</p>
</div>
);
}
4) Un handleChange générique
Au lieu d’écrire 3 fonctions différentes, on crée une seule fonction
qui sait quel champ est en train de changer.
Pour cela, on utilise name sur l’input.
A) Les inputs doivent avoir un attribut name
<input name="firstname" value={form.firstname} onChange={handleChange} />
<input name="email" value={form.email} onChange={handleChange} />
<input name="city" value={form.city} onChange={handleChange} />
B) La fonction générique
const handleChange = (e) => {
const { name, value } = e.target;
setForm((prev) => ({
...prev,
[name]: value
}));
};
Ici, [name] est une “clé dynamique” : si name === "email",
alors on met à jour form.email.
5) Soumission : onSubmit + preventDefault
On place l’handler sur la balise <form>. On empêche le rechargement avec preventDefault.
const handleSubmit = (e) => {
e.preventDefault();
console.log("Données envoyées :", form);
};
6) Validations simples (débutant)
Avant d’envoyer les données, on vérifie quelques règles. Exemple :
- Prénom obligatoire
- Email doit ressembler à un email
- Ville obligatoire
const validate = () => {
const errors = {};
if (!form.firstname.trim()) errors.firstname = "Le prénom est requis.";
if (!form.city.trim()) errors.city = "La ville est requise.";
const emailOk = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(form.email);
if (!emailOk) errors.email = "Email invalide.";
return errors;
};
7) Afficher les erreurs proprement
On stocke les erreurs dans un state séparé errors.
Puis on affiche l’erreur sous chaque champ si elle existe.
const [errors, setErrors] = useState({});
const handleSubmit = (e) => {
e.preventDefault();
const validationErrors = validate();
setErrors(validationErrors);
if (Object.keys(validationErrors).length === 0) {
console.log("OK, on peut envoyer :", form);
}
};
Afficher sous un champ
<input name="email" value={form.email} onChange={handleChange} />
{errors.email && <p>{errors.email}</p>}
Ici, l’erreur s’affiche uniquement si errors.email existe.
8) Réinitialiser le formulaire
Après un envoi réussi, vous voudrez souvent remettre les champs à zéro.
const initialForm = { firstname: "", email: "", city: "" };
const [form, setForm] = useState(initialForm);
const resetForm = () => {
setForm(initialForm);
setErrors({});
};
9) Bonus : checkbox et select
Checkbox : on lit e.target.checked (un booléen), pas value.
const handleChange = (e) => {
const { name, type, value, checked } = e.target;
setForm((prev) => ({
...prev,
[name]: type === "checkbox" ? checked : value
}));
};
Pour un <select>, on récupère simplement value, comme un input texte.
10) Résumé (à retenir)
- Un formulaire React “pro” utilise des champs contrôlés.
- Pour plusieurs champs, un state objet
formest très pratique. - Un
handleChangegénérique utilisename+[name]. - Validation simple : fonction
validate()→ objeterrors. - On affiche chaque erreur sous le champ correspondant.
11) Exercice pratique
Créez un formulaire “Inscription” avec :
- Prénom (obligatoire)
- Email (format email)
- Ville (obligatoire)
- Une checkbox “J’accepte les conditions” (obligatoire)
Contraintes
- Utilisez un seul state objet pour les champs.
- Utilisez un handleChange générique.
- Affichez les erreurs sous chaque champ.
- Si tout est OK, affichez un message “Inscription réussie” et réinitialisez le formulaire.
Prochaine étape : Chapitre 17 — Introduire le Context API pour éviter le “props drilling” quand l’application grandit.