Maîtrisez les événements en React
Si vous avez déjà manipulé du JavaScript, vous êtes sûrement déjà familier avec les événements. Bon, vous avez quand même droit à un petit rappel : un événement est une réaction à une action émise par l'utilisateur, comme le clic sur un bouton ou la saisie d'un texte dans un formulaire.
Bonne nouvelle pour vous : avec sa syntaxe pratique et concise, React facilite énormément la gestion des événements du DOM. 🎉
Familiarisez-vous avec la syntaxe
Quelques caractéristiques de la déclaration d'un événement en React :
l'événement s'écrit dans une balise en
camelCase
;vous déclarez l'événement à capter, et lui passez entre accolades la fonction à appeler ;
contrairement au JS, dans la quasi totalité des cas, vous n'avez pas besoin d'utiliser
addEventListener
.
Testons ça dès maintenant dans notre code. Dans components/PlantItem.js
, je vais déclarer une fonction handleClick
qui vient faire un log dans notre console :
function handleClick() {
console.log('✨ Ceci est un clic ✨')
}
On ajoute maintenant onClick={handleClick}
dans la bali
se li du composant PlantItem
. On a donc :
<li className='lmj-plant-item' onClick={handleClick}>
<img className='lmj-plant-item-cover' src={cover} alt={`${name} cover`} />
{name}
<div>
<CareScale careType='water' scaleValue={water} />
<CareScale careType='light' scaleValue={light} />
</div>
</li>
J'ouvre la console : yeeeees ! Ça fonctionne comme prévu ! 🎉
Je vais pousser cet exercice un peu plus loin : on va déclencher une alerte qui affiche le nom de la plante sur laquelle on a cliqué.
On passe donc plantName
en paramètre de handleClick comme ici :
function handleClick(plantName) {
alert(`Vous voulez acheter 1 ${plantName} ? Très bon choix 🌱✨`)
}
Mais si je clique, ça ne marche pas :
En effet, React passe par défaut un objet (que nous aborderons dans quelques minutes), mais ici, nous voulons lui spécifier notre propre argument.
Pour cela, c'est très simple : on déclare une fonction directement dans onClick
(les fonctions fléchées sont très pratiques pour ça). Cette fonction appellera handleClick en lui passant name
en paramètre. Donc on a :
onClick={() => handleClick(name)}
Essayez pour voir !
Et voilà ! 😎
Découvrez les événements synthétiques
Donc, je vous parlais de l'objet que React passe par défaut en paramètre aux fonctions indiquées en callback des événements. Voyons voir à quoi ça ressemble. 🕵️♀️
Si je récupère le paramètre dans handleClick :
function handleClick(e) {
console.log('✨ Ceci est mon event :', e)
}
j'obtiens ça :
Allez-y, essayez de le faire par vous-même !
Ça nous donne beaucoup d'informations, n'est-ce pas ? Mais à quoi ça correspond ? 🤔
Il s'agit en fait d'un événement synthétique. Pour faire bref, il s'agit de la même interface que pour les événements natifs du DOM, sauf qu'ils sont compatibles avec tous les navigateurs.
Pratique, n'est-ce pas ?
Vu qu'il s'agit de la même interface que pour les événements natifs du DOM, est-ce qu'on a aussi accès à preventDefault
et stopPropagation
?
Tout à fait ! Vous pouvez utiliser ces méthodes avec le paramètre récupéré dans la fonction passée à l'événement. Dans notre cas, vous auriez pu faire e.preventDefault()
. Si vous avez besoin de rafraîchir vos connaissances sur preventDefault
et stopPropagation
, je vous renvoie sur le chapitre événements de l'excellent cours "Apprenez à programmer avec JavaScript".
Simplifiez votre création de formulaires avec React
En React, la gestion des formulaires est simplifiée : on a accès à la valeur très facilement, qu'il s'agisse d'un input checkbox, d'un textarea, ou encore d'un select avec onChange
.
Il existe deux grandes manières de gérer les formulaires : la manière contrôlée et la manière non contrôlée. J'aborderai assez rapidement la manière non contrôlée, parce qu'elle nécessite moins d'implication de React, et que React encourage l'utilisation des formulaires contrôlés.
Déléguez le contrôle : les formulaires non contrôlés
Je vous fais une petite démo d'un formulaire non contrôlé. Sur notre app, directement dans App.js
, je mets un composant QuestionForm
que je vais déclarer dans un fichier à part. Nous allons ajouter un champ pour une question.
Donc pour ça je crée un form, qui englobe mon input :
<form onSubmit={handleSubmit}>
<input type='text' name='my_input' defaultValue='Tapez votre texte' />
<button type='submit'>Entrer</button>
</form>
Et pour handleSubmit
, cela donne :
function handleSubmit(e) {
e.preventDefault()
alert(e.target['my_input'].value)
}
Vous voyez que React me permet de préciser une defaultValue
à mon champ input. Ici, j'appelle preventDefault
, sinon le submit
rafraîchirait la page.
Et j'ai bien mon alerte qui se déclenche. 🎉
Plutôt simple, n'est-ce pas ? Vous déléguez le travail à votre DOM. Effectivement, les formulaires non contrôlés nous permettent de ne pas avoir à gérer trop d'informations. Mais cette approche est un peu moins "React", parce qu'elle ne permet pas de tout faire.
À la place, vous pouvez utiliser les composants contrôlés.
Contrôlez vos formulaires
Le state local nous permet de garder des informations. Ces informations sont spécifiques à un composant et elles proviennent d'une interaction que l'utilisateur a eue avec le composant.
Donc je vais créer ma variable inputValue
et la fonction qui va permettre de changer sa valeur dans le state local avec useState
.
Sachez juste que la ligne de code ci-dessous me permet de déclarer l'état initial pour inputValue
et la fonction correspondante pour la modifier, et de lui préciser la valeur par défaut "Posez votre question ici" :
const [inputValue, setInputValue] = useState("Posez votre question ici")
J'ai donc mon QuestionForm
comme ci-dessous :
import { useState } from 'react'
function QuestionForm() {
const [inputValue, setInputValue] = useState('Posez votre question ici')
return (
<div>
<textarea
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
/>
</div>
)
}
export default QuestionForm
Ici, je passe une fonction en callback à onChange
pour qu'elle sauvegarde dans mon state local la valeur de mon input. J'accède à la valeur tapée dans l'input avec e.target.value
.
inputValue
a maintenant accès au contenu de mon input à tout moment. Je peux donc créer un bouton qui déclenche une alerte qui affiche le contenu de mon input, comme ici :
<div>
<textarea
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
/>
<button onClick={() => alert(inputValue)}>Alertez moi 🚨</button>
</div>
Et ça marche bien !
C'est bien beau d'avoir accès à la valeur de mon input, mais pourquoi ? 🤔
Comprenez les avantages des formulaires contrôlés
Eh bien, cela permet d'interagir directement avec la donnée renseignée par l'utilisateur. Vous pouvez donc afficher un message d'erreur si la donnée n'est pas valide, ou bien la filtrer en interceptant une mauvaise valeur.
Si nous décidons qu'il n'est pas autorisé d'utiliser la lettre "f" (bon oui, c'est un peu bizarre), eh bien nous pouvons déclarer une variable :
const isInputError = inputValue.includes('f')
et afficher ou non un message d'erreur en fonction de ce booléen :
{isInputError && (
<div>🔥 Vous n'avez pas le droit d'utiliser la lettre "f" ici.</div>
)}
De la même manière, nous pouvons intercepter une mauvaise valeur entrée par l'utilisateur. Pour cela, il faut déclarer une fonction intermédiaire :
function checkValue(value) {
if (!value.includes('f')) {
setInputValue(value)
}
}
et on applique la modification dans notre fonction callback :
onChange={(e) => checkValue(e.target.value)}
Ici, vous aurez beau marteler votre touche `f` autant de fois que vous voudrez, la valeur ne s'inscrira pas dans votre input.
Vous ne vous en rendez peut-être pas compte pour l'instant, mais ça vous laisse une très grande liberté quant aux validations que vous voulez créer ; et en tant que développeur, c'est vraiment très puissant 🔥.
Super, je connais les deux méthodes, mais quand utiliser le composant contrôlé et quand utiliser sa version non contrôlée ?!
Eh bien cela dépend des cas. À vous de voir selon vos contraintes. Quand vous avez un composant rapide à faire, qui n'intègre aucune complexité, un input non contrôlé peut faire l'affaire. À l'inverse, si vous avez des vérifications à faire, il vaudra sûrement mieux passer par un composant contrôlé. Pour ma part, j'ai vu beaucoup plus de composants contrôlés dans les codebases que j'ai pu voir.
Sachez qu'il existe également des bibliothèques qui vous permettent de gérer les formulaires et leur validation aussi proprement que possible, par exemple le très bon outil react-hook-form
.
Et voilà, vous êtes maintenant équipé pour interagir avec vos utilisateurs grâce aux événements et aux formulaires. 😎
Exercez-vous
Vous allez maintenant pouvoir mettre tout ça en application. Comme d'habitude, vous trouverez la base de code pour commencer l'exercice sur P2C5-Begin.
Cette fois-ci, voilà une petite to do de ce que vous pouvez faire pour enrichir notre app :
Créer une alerte qui se déclenche au clic sur le composant CareScale qui devra dire :
"Cette plante requiert peu/modérement/beaucoup de lumière/d'arrosage" en fonction de la donnée correspondante ;
s'il s'agit d'un composant CareScale de type "water" ou de type "light".
Vous trouverez dans la base de code un nouveau composant :
Footer
. Vous devez y ajouter :un input pour récupérer le mail de l'utilisateur, en appliquant la méthode de composant contrôlé. La syntaxe du state que nous avons utilisée dans ce chapitre pour
inputValue
etsetInputValue
qui utilise useState est d'ailleurs déjà écrite dans la base de code ;l'événement
blur
(quand on clique en dehors du champ) qui déclenche une alerte si inputValue ne contient pas le caractère "@". Cette alerte devra préciser "Attention, il n'y a pas d'@, ceci n'est pas une adresse valide.”
La solution se trouve sur la branche P2C5-Solution.
En résumé
En React, un événement s'écrit dans une balise en
camelCase
, et on lui passe la fonction à appeler.Contrairement au JS, dans la quasi totalité des cas, vous n'avez pas besoin d'utiliser
addEventListener
.React passe un événement synthétique en paramètre des fonctions de callBack. Cet événement synthétique est similaire à un événement passé en natif dans le DOM, sauf qu'il est compatible avec tous les navigateurs.
Il existe deux grandes manières de gérer les formulaires : les formulaires contrôlés ou non contrôlés. L'utilisation des formulaires contrôlés est recommandée.
Les formulaires contrôlés sauvegardent la valeur des champs dans le state local, et accèdent à la data entrée par l'utilisateur avec
onChange
.Les formulaires contrôlés permettent de filtrer le contenu, ou d'afficher un message d'erreur en fonction de la data qui est entrée par l'utilisateur.
Nous voilà à nouveau à la fin d'une partie. Vous allez pouvoir vérifier vos acquis dans le quiz. Puis, une fois que ce sera fait, vous allez pouvoir vous lancer dans le state avec React ! 🚀