Apprends comment React gère les interactions utilisateur avec son système d'événements synthétiques, incluant les clics, les entrées de formulaire et les événements clavier.
En JavaScript pur, tu gères les événements en appelant addEventListener sur un élément DOM. En React, tu gères les événements directement dans le JSX en utilisant des props spéciales qui commencent par on suivi du nom de l'événement en camelCase.
| JavaScript pur | React JSX |
|---|---|
element.addEventListener('click', handler) | <button onClick={handler}> |
element.addEventListener('change', handler) | <input onChange={handler}> |
element.addEventListener('submit', handler) | <form onSubmit={handler}> |
element.addEventListener('keydown', handler) | <input onKeyDown={handler}> |
element.addEventListener('mouseover', handler) | <div onMouseOver={handler}> |
Remarque la convention de nommage : toutes les props d'événements utilisent le camelCase — onClick et non onclick, onChange et non onchange, onKeyDown et non onkeydown.
Voici un simple gestionnaire de clic :
function App() {
function handleClick() {
alert('Le bouton a été cliqué !');
}
return <button onClick={handleClick}>Clique-moi</button>;
}Important : Tu passes la référence de la fonction, pas un appel de fonction :
// CORRECT — passe la référence de la fonction
<button onClick={handleClick}>Cliquer</button>
// INCORRECT — appelle la fonction immédiatement au rendu !
<button onClick={handleClick()}>Cliquer</button>Avec la mauvaise version, handleClick() s'exécute à chaque fois que le composant est rendu, pas quand le bouton est cliqué. C'est une erreur très courante chez les débutants.
Tu peux aussi utiliser des fonctions flèches inline pour des gestionnaires courts :
<button onClick={() => console.log('Cliqué !')}>Cliquer</button>Quand un événement se déclenche, React passe un objet SyntheticEvent à ta fonction gestionnaire. C'est le propre objet événement de React qui enveloppe l'événement natif du navigateur et fournit une API cohérente sur tous les navigateurs.
function App() {
function handleClick(event) {
console.log(event.type); // 'click'
console.log(event.target); // l'élément DOM cliqué
console.log(event.clientX); // position X de la souris
}
return <button onClick={handleClick}>Clique-moi</button>;
}Le SyntheticEvent a la même interface que l'événement natif du navigateur, donc toutes les propriétés que tu connais du JavaScript vanilla fonctionnent : event.target, event.currentTarget, event.type, etc.
event.preventDefault() fonctionne comme en JavaScript vanilla — il empêche le comportement par défaut du navigateur :
function ContactForm() {
function handleSubmit(event) {
event.preventDefault(); // Empêche le rechargement de la page
console.log('Formulaire soumis !');
}
return (
<form onSubmit={handleSubmit}>
<input type="text" name="email" />
<button type="submit">Envoyer</button>
</form>
);
}Sans preventDefault(), soumettre un formulaire provoque le rechargement de la page par le navigateur. Dans une application React, tu veux presque toujours empêcher cela et gérer la soumission en JavaScript à la place.
event.stopPropagation() empêche l'événement de remonter vers les éléments parents :
function App() {
return (
<div onClick={() => console.log('div cliqué')}>
<button onClick={(e) => {
e.stopPropagation();
console.log('bouton cliqué');
}}>
Clique-moi
</button>
</div>
);
}
// Affiche seulement 'bouton cliqué', pas 'div cliqué'Un des patterns d'événements les plus courants en React est la gestion des entrées de texte. Tu utilises l'événement onChange combiné avec useState pour créer ce que React appelle un composant contrôlé — une entrée dont la valeur est pilotée par l'état React.
function SearchBox() {
const [query, setQuery] = React.useState('');
function handleChange(event) {
setQuery(event.target.value);
}
return (
<div>
<input
type="text"
value={query}
onChange={handleChange}
/>
<p>Recherche pour : {query}</p>
</div>
);
}Voici ce qui se passe à chaque frappe de touche :
onChange.handleChange appelle setQuery(event.target.value) avec la nouvelle valeur de l'entrée.query.L'attribut value={query} fait de ceci une entrée contrôlée — React est la source unique de vérité pour la valeur de l'entrée. Cela te donne un contrôle total : tu peux valider, transformer ou rejeter l'entrée avant qu'elle n'apparaisse.
// Autoriser seulement les chiffres
function NumberInput() {
const [value, setValue] = React.useState('');
function handleChange(event) {
const newValue = event.target.value;
// Mettre à jour seulement si l'entrée contient des chiffres ou est vide
if (/^\d*$/.test(newValue)) {
setValue(newValue);
}
}
return <input value={value} onChange={handleChange} />;
}Tu peux aussi écrire le gestionnaire inline pour les cas plus simples :
<input
value={query}
onChange={(e) => setQuery(e.target.value)}
/>Parfois tu dois passer des données supplémentaires à un gestionnaire d'événements — par exemple, quel élément d'une liste a été cliqué. Le pattern standard est d'envelopper le gestionnaire dans une fonction flèche :
function TodoList() {
const [todos, setTodos] = React.useState([
{ id: 1, text: 'Apprendre React' },
{ id: 2, text: 'Construire un projet' },
{ id: 3, text: 'Le déployer' },
]);
function handleDelete(id) {
setTodos(todos.filter(todo => todo.id !== id));
}
return (
<ul>
{todos.map(todo => (
<li key={todo.id}>
{todo.text}
<button onClick={() => handleDelete(todo.id)}>
Supprimer
</button>
</li>
))}
</ul>
);
}La fonction flèche () => handleDelete(todo.id) crée une nouvelle fonction qui "capture" le todo.id spécifique pour chaque élément de la liste. Quand le bouton est cliqué, elle appelle handleDelete avec l'ID correct.
Tu peux toujours accéder à l'objet événement en plus de tes arguments personnalisés :
function handleClick(id, event) {
console.log('ID de l\'élément :', id);
console.log('Événement :', event.type);
}
<button onClick={(event) => handleClick(item.id, event)}>
Cliquer
</button>Types d'événements courants que tu utiliseras souvent :
onClick — Boutons, éléments cliquablesonChange — Entrées de texte, sélecteurs, cases à cocheronSubmit — FormulairesonKeyDown / onKeyUp — Raccourcis clavieronFocus / onBlur — Suivi du focus des entréesonMouseEnter / onMouseLeave — Effets de survol<div id="root"></div>
<script src="https://unpkg.com/react@19/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@19/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
function App() {
const [query, setQuery] = React.useState("");
const fruits = ["Apple", "Banana", "Cherry", "Date", "Elderberry", "Fig", "Grape"];
const filtered = fruits.filter(fruit =>
fruit.toLowerCase().includes(query.toLowerCase())
);
return (
<div style={{ padding: "20px" }}>
<h2>Recherche de fruits</h2>
<input
type="text"
placeholder="Rechercher des fruits..."
value={query}
onChange={(e) => setQuery(e.target.value)}
style={{ padding: "8px", fontSize: "16px", width: "200px" }}
/>
<ul>
{filtered.map((fruit, i) => (
<li key={i}>{fruit}</li>
))}
</ul>
<p>{filtered.length} résultat(s)</p>
</div>
);
}
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
</script>Quelle est la différence entre `onClick={handleClick}` et `onClick={handleClick()}` ?