Conclusion module formulaires
Maîtrise les formulaires avec React Router 7, Conform et Zod : UX fluide, validation sécurisée, typage total, et zéro état local pour un code propre et robuste en production.
Ce que tu retiens vraiment de ce module
Félicitations ! Tu viens de parcourir l’intégralité du module dédié aux formulaires dans React Router 7. Au-delà de la simple technique, voici les idées maîtresses que tu dois impérativement garder en tête :
- Expérience développeur hors-norme
<Form>+ duoloader / action= cycle automatique :loader → action → loader, sans fetch manuel, sansuseEffect.- Le code reste lisible, sans état local parasite ni calls d’API dispersés.
- Expérience utilisateur premium
- Aucun « flash » entre deux soumissions, pas d’écran blanc ni erreur 500 incontrôlée.
- Validation temps réel : l’utilisateur sait immédiatement pourquoi son champ est invalide et où corriger.
- Sécurité & robustesse
- Les règles Zod bloquent toutes les entrées invalides côté serveur ; un cURL ou Postman ne passera pas.
- Pas de base de données corrompue, pas d’exception inattendue.
- Conform & Zod = un seul langage métier
- Un schéma unique pour le client et le serveur.
- Génération auto des
required,minLength, focus sur le premier champ fautif, messages d’erreur cohérents.
- Hooks avancés
useFetcherpour les interactions sans navigation (autosave, boutons « Like »).useSubmitquand tu transformes un composant custom en déclencheur de formulaire.
Du prototype à la vraie vie : la suite du programme
Le module a volontairement utilisé une “base de données en mémoire” pour te laisser te concentrer sur la mécanique des formulaires. Mais dans une application production :
- les données persistent dans Postgres, MySQL ou Mongo ;
- tu dois gérer l’authentification, protéger certaines routes, stocker un cookie de session, etc.
C’est exactement ce que nous attaquons dans le prochain module :
1# Objectifs du chapitre suivant2✅ brancher une vraie DB (Prisma + SQLite pour débuter)3✅ implémenter l'inscription / connexion4✅ créer des routes protégées et des redirects automatiques
Grâce à tout ce que tu viens d’apprendre — validation partagée, cycle loader/action, gestion d’erreurs fine — tu verras que connecter un vrai back-end devient presque trivial.
Récap technique express
| Concept | API React Router 7 | Lib associée |
|---|---|---|
| Soumission classique | <Form method="POST"> | react-router |
| Soumission sans navigation | useFetcher() | react-router |
| Déclenchement programmatique | useSubmit() | react-router |
| Validation type-safe (client) | useForm() | Conform |
| Validation type-safe (serveur) | parseWithZod() | Zod |
| Schéma unique, contraintes HTML | getZodConstraint() | Conform + Zod |
| Gestion d’erreurs serveur | submission.reply() | Conform |
Astuce : garde toujours ce tableau dans un coin de ton IDE ; il te sert de pense-bête sur les couples « problème / solution ».
Petit coup d’œil au code final
1import { Form, useActionData, useLoaderData } from "react-router"2import {3useForm, getFormProps, getInputProps, getZodConstraint,4} from "@conform-to/react"5import { parseWithZod } from "@conform-to/zod"6import { userActionSchema } from "~/schemas/user"78export async function action({ request }) {9const submission = await parseWithZod(request.formData(), {10schema: userActionSchema,11})12if (submission.status !== "success") {13return data({ result: submission.reply() }, { status: 400 })14}15/* mutation */16}1718export default function UserForm() {19const loaderData = useLoaderData<typeof loader>()20const actionData = useActionData<typeof action>()21const [form, fields] = useForm({22id: "user-form",23lastResult: actionData?.result,24constraint: getZodConstraint(userActionSchema),25onValidate: ({ formData }) =>26parseWithZod(formData, { schema: userActionSchema }),27defaultValue: loaderData.defaultValue,28})2930return (31<Form method="POST" {...getFormProps(form)} className="space-y-4">32<input {...getInputProps(fields.action, { type: "hidden" })} />33{/* …autres champs */}34<button disabled={form.submission?.pending} className="btn-primary">35{form.submission?.pending ? "Sauvegarde…" : "Enregistrer"}36</button>37</Form>38)39}
Observe : aucun useState, pas de try/catch, zéro duplication
entre client et serveur — et pourtant le formulaire est :
- accessible (ARIA),
- validé à deux niveaux,
- typé de bout en bout.
À tout de suite dans le module Authentification : on branche la base de données, on sécurise les routes, et tu verras que les fondations posées ici feront toute la différence.
Comprendre les concepts fondamentaux
Quelle est la principale différence entre les composants client et serveur dans React ?
Optimisation des performances
Quelle technique est recommandée pour éviter les rendus inutiles dans React ?
Architecture des données
Quel hook permet de gérer les effets de bord dans un composant React ?