Les inputs contrôlés et non contrôlés sont deux approches différentes pour gérer les saisies utilisateur dans les formulaires React.
Dans le cas des inputs contrôlés, l'état du formulaire est géré par React, et la valeur de chaque input est liée à une variable d'état via l'attribut `value`. Cette approche assure un contrôle total sur les données saisies et permet de réaliser des opérations de validation et ou de formatage avant la soumission du formulaire.
Dans le cas, des inputs non contrôlés, React ne gère pas l'état des inputs. A la place, la valeur des inputs est déterminée par le DOM via l'attribut `defaultValue`. Les données sont récupérées directement à partir du DOM généralement lors de la soumission du formulaire. Bien que cette approche soit plus simple à mettre en œuvre, elle peut entraîner des difficultés lorsqu'il s'agit de valider les données en temps réel ou de contrôler finement le comportement des formulaires.
Un "controlled" input c'est un input qui est géré via un state. Le contrôle de sa valeur est lié à celui-ci. Il ne peut pas être modifié. Le seul moyen pour pouvoir modifier sa valeur est d'utiliser un useState et l'évènement onChange
const controlledInput = () => {
const [value, setValue] = useState("");
return (
<input value={value}
onChange = { (evt) => { setValue(e.target.value)}} />
)
}
Le problème avec cette manière de faire, c'est qu'à chaque fois que l'utilisateur tape une lettre, ça provoque un re-rendu de notre input. En effet la valeur de notre input n'est pas gérée par le DOM mais par React.
Voici un exemple de formulaire simple avec des input contrôlés :
const SignUp = () => {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const handleSubmit = () => {
alert(`${name} ${email}`);
};
return (
<form>
<label htmlFor="name">Nom : </label>
<input type="text"
id="name"
value={name}
onChange={(e) => setName(e.target.value)} />
<label htmlFor="email">Email : </label>
<input type="email"
id="email"
value={email}
onChange={(e) => setEmail(e.target.value)} />
<button onClick={handleSubmit}>Envoyer</button>
</form>
);
};
Les inputs contrôlés présentent plusieurs avantages. En contrôlant l'état des inputs, il est facile de mettre en œuvre des validations en temps réel et ainsi d'empêcher les soumissions invalides avant leur envoi.
Cependant, cette approche peut nous faire écrirer plus de code, surtout pour des formulaires complexes. Chaque input nécessite la création d'une variable d'état, et des re-renders fréquents surviennent lors de la mise à jour des valeurs. Ces inconvénients peuvent être négligeables, mais ils peuvent impacter les performances de l'application pour des formulaires plus complexes et volumineux.
Pour optimiser les performances, une astuce courante consiste à utiliser un délai (*debounce*) pour réduire le nombre de re-renders lorsqu'un utilisateur saisit un champ. Cela permet d'éviter des mises à jour inutiles du DOM à chaque frappe et de rendre l'expérience plus fluide.
Un "uncontrolled" input c'est un input dont la valeur est gérée par le DOM et il le fait très bien. N'oubliez pas que c'est un composant HTML natif qui a pour but d'interagir avec l'utilisateur.
Pour qu'un input soit un "uncontrolled" input, dans React il suffit de mettre l'attribut spécial `defaultValue`.
const unControlledInput = () => {
return <input defaultValue={''} />
}
Voici le même exemple de formulaire que plus haut, mais cette fois, avec des input non contrôlés :
const SignUp = () => {
const handleSubmit = (evt) => {
const form = evt.currentTarget;
// En utilisant formData (recommandé)
// Il ne faut pas oublié de rajouter
// l'attribut name dans les inputs
const formData = new formData(form)
const name = formData.get('name');
const email = formData.get('email');
/* Sans formData
const name = form.elements.name.value;
const email = form.elements.email.value;
*/
alert(`${name} ${email}`);
/* reinitialise le formulaire */
form.reset();
};
return (
<form onSubmit={handleSubmit}>
<label htmlFor="name">Nom : </label>
<input type="text"
id="name"
name="name"/>
<label htmlFor="email">Email : </label>
<input type="email"
id="email"
name="email"/>
<button type="submit">Envoyer</button>
</form>
);
};
Ici, il n'y aura pas de re-rendu.
Notez que ici vu que les inputs sont englobés dans un form, l'attribut defaultValue n'est pas obligatoire.
Les inputs non contrôlés, sont plus faciles à implémenter pour des cas simple où la validation en temps réel n'est pas essentielle.
Ils évitent la création de variables d'état (*state*) pour chaque input. Cependant, cette approche limite la possibilité de réaliser des opérations de validation en temps réel et sont plus difficiles à mettre en place. Les données sont récupérées qu'au moment de la soumission.
Utiliser un input contrôlé :
Utiliser un input non contrôlé :
Nous avons vu la différence entre input contrôlé et non contrôlé.
Nous avons vu quand les utiliser globalement.
De manière générale, utiliser des inputs non contrôlés est souvent la meilleure façon de faire dans la majorité des cas. Cela évite les re-rendu, on a donc une interface plus fluide. Le désavantage (négligeable, à mon avis) c'est que la validation des données et l'affichage des messages d'erreurs si besoin se font à la soumission du formulaire.
Pour vous simplifier la vie avec les formulaires (validations, formulaires complexes) je vous recommande d'utiliser la bibliothèque react-use-fom.
Que vous essayiez de scaler votre start-up, de créer votre premier site internet ou de vous reconvertir en tant que développeur, Believemy est votre nouvelle maison. Rejoignez-nous, évoluez et construisons ensemble l’avenir.