Comment faire de bon formulaire en React ?

June 23, 202221 min read

banner url

Il y a plus de moyens de faire des formulaires en React que de framework JS. C'est pour ça que j'ai envie de parler d'un concept que j'ai, à l'époque, pris longtemps à comprendre : les formulaires en React.

Dans cet article on va comprendre le problème à utiliser des useState en React, on va comparer les libraries disponibles ainsi que la façon la plus simple de gérer un formulaire.

Controlled, uncontrolled input ?

Arrêtons-nous sur cette simple definition.

Un controlled input, c'est un input qui est géré par un state. La valeur affichée est totalement liée au state.

const Controlled = () => {
  return <input value="controlled" readOnly />;
};

const Uncontrolled = () => {
  return <input defaultValue={'Uncontrolled'} />;
};

Si tu ne met pas de readOnly, tu vas avoir un warning dans la console car tu n'as pas ajouté de onChange. L'utilisateur ne pourra pas modifier la valeur.

Le controlled ne peut pas être modifié. Le seul moyen de pouvoir le modifier est d'utiliser un useState React :

const Controlled = () => {
  const [value, setValue] = useState('controlled');
  return <input value={value} onChange={(e) => setValue(e.target.value)} />;
};

Mais là, on va donc gérer une valeur... qui est déjà gérée par défaut 🤡 Le comportement est exactement le même ici qu'avec un input uncontrolled.

Mais pourquoi il n'y a pas de "controlled div" alors ?

Tout simplement, car un "controlled input" c'est un input dont la valeur est gérée, et comme tu le sais la valeur d'un input peut être modifiée, car c'est un composant qui a pour but d'interagir avec l'utilisateur.

La valeur d'un input tu peux la voir comme un state, qui est géré par le DOM. Quand tu "contrôle" cette input tu viens contrôler ce state. Un div n'a pas de state, donc rien à contrôler.

Pour comprendre un peu le flux, je t'ai fais un petit "schéma" interactif !

Voilà ce que React va devoir faire à chaque fois. Il va "repeindre" l'écran avec ta nouvelle valeur.

C'est ce qu'on appelle les inputs controllers.

Faire un formulaire simplement

Voici un exemple d'un formulaire controller :

const MyForm = () => {
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');

  const onSubmit = () => {
    alert(`Submitted ${name} ${email}`);
  };

  return (
    <form>
      <input value={name} onChange={(e) => setName(e.target.value)} />
      <input value={email} onChange={(e) => setEmail(e.target.value)} />
      <button onClick={onSubmit}>Submit</button>
    </form>
  );
};

Et un exemple d'un formulaire pas controllé :

const MyForm = () => {
  const onSubmit = (event) => {
    event.preventDefault();

    const form = event.currentTarget;

    const name = form.elements.name.value;
    const email = form.elements.email.value;

    alert(`Submitted ${name} ${email}`);
  };

  return (
    <form className="flex flex-col gap-2 p-2" onSubmit={onSubmit}>
      <input type="text" id="name" />
      <input type="email" id="email" />
      <button type="submit">Submit</button>
    </form>
  );
};

L'implémentation n'est pas drastiquement différente, mais quelques détails :

  • Ajout d'un id dans les input afin de pouvoir les récupérer plus facilement
  • la fonction onSubmit est dans le form et pas le button car le button type="submit" va trigger le onSubmit du form.

Comparons les deux formulaires :

Controlled

Uncontrolled

Test les deux formulaires, avec le bouton submit.

Les deux fonctionnent mais l'un ne fait que de bipper vert. Chaque fois que le background devient vert c'est que le composant a rerender. Le lifecycle qu'on a vu avant se produit ici. Inutilement car, à droite, ça fonctionne pareil sans rerender.

Quand utiliser controlled ou uncontrolled ?

Tu peux utiliser controlled quand :

✅ Tu as besoin de gérer la valeur liée au state et tu ne fais pas que de la lecture, mais aussi de l'écriture. Donc tu modifies le state en utilisant setState. Par exemple dans un AutoComplete.

❌ Si tu souhaites juste effectuer une action quand tu changes la valeur de l'input il ne faut pas écouter la valeur avec un useEffect mais juste utiliser le onChange pour effectuer des modifications.

❌ Si tu souhaites juste lire la valeur de l'input, tu peux utiliser une ref.

❌ Si tu souhaites faire un formulaire, utilise l'api de form ou react-use-form.

Pour la gestion d'erreur, par contre il est obligatoire d'utiliser un state. Mais attention, tu te retrouves vite avec des choses complexes et chiantes à gérer si tu fais tout à la main... Genre ce code :

const [errors, setErrors] = useState({ name: null, email: null });

const onSubmit = (e) => {
  const name = form.elements.name.value;
  const email = form.elements.email.value;

  let errors = { name: null, email: null };

  if (!name) errors.name = 'Name is required';

  if (!email) errors.email = 'Email is required';

  // email length
  if (email.length > 50) errors.email = 'Email is too long';

  if (email.length < 5) errors.email = 'Email is too short';

  if (errors.name || errors.email) {
    setErrors(errors);
    return;
  }

  alert(name, email);
};

Sur l'échelle de l'enfer, ce code est à un bon niveau. C'est pour cette raison que je te recommande fortement d'utiliser react-use-form.

Conclusion

Nous avons vu la différence entre controlled et uncontrolled et nous avons compris le lifecycle d'un input controlled. Nous avons pu voir quelles étaient leurs différences dans le cas d'un formulaire basique.

Nous savons maintenant quand utiliser ou ne pas utiliser controlled ou uncontrolled.

En règle générale, utiliser uncontrolled est la meilleure option. Tu as de nombreux moyen d'en faire avec des référence, des formData ou des librairies comme react-use-form.

Un formulaire controlled te seras utiles uniquement pour un search input ou pour une donnée que tu souhaites contrôler...

Cette article à été créer pour la formation BeginReact.dev !

logo

BeginReact.dev

Arrête de douter...
Et viens dompter React 🦁 !

Regarde la vidéo masterclass


my profile picture

Écris par Melvyn Malherbe

J'ai aidé 200 personnes à apprendre React et Next.js. Je suis un créateur de contenu et un développeur web. Plus de 2'600 personnes reçoivent mes newsletter par email chaque semaine.

En apprendre plus à propos de moi