React Js Ed1 v1
React Js Ed1 v1
React Js Ed1 v1
É. Sarrion
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Un ouvrage de référence pour les développeurs web
React.js
En tant que développeur, qui n’a pas encore entendu parler de React.js (ou React de façon raccourcie) ? Cette bibliothèque JavaScript,
initialement écrite pour Facebook (en 2013), s’utilise maintenant couramment dans le monde de l’entreprise. Elle permet de structurer
efficacement une application web, mais peut également s’utiliser dans une version dite native, pour écrire des applications mobiles à
destination des iPhone ou Android.
Cet ouvrage vous permettra entre autres de créer des applications web autonomes, mais également de les interfacer avec un serveur
en utilisant Ajax. Et surtout, vous comprendrez comment augmenter la complexité de votre application tout en conservant un code bien
structuré, ceci grâce à React mais aussi Redux, étudié dans les derniers chapitres de l’ouvrage.
Agrémenté de nombreuses illustrations et de cas pratiques, cet ouvrage vous accompagne de façon progressive dans la
découverte des concepts et propriétés associés à ce nouveau framework.
32 E
É. Sarrion
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
React.js
En tant que développeur, qui n’a pas encore entendu parler de React.js (ou React de façon raccourcie) ? Cette bibliothèque JavaScript,
initialement écrite pour Facebook (en 2013), s’utilise maintenant couramment dans le monde de l’entreprise. Elle permet de structurer
efficacement une application web, mais peut également s’utiliser dans une version dite native, pour écrire des applications mobiles à
destination des iPhone ou Android.
Cet ouvrage vous permettra entre autres de créer des applications web autonomes, mais également de les interfacer avec un serveur
en utilisant Ajax. Et surtout, vous comprendrez comment augmenter la complexité de votre application tout en conservant un code bien
structuré, ceci grâce à React mais aussi Redux, étudié dans les derniers chapitres de l’ouvrage.
Agrémenté de nombreuses illustrations et de cas pratiques, cet ouvrage vous accompagne de façon progressive dans la
découverte des concepts et propriétés associés à ce nouveau framework.
React.js
67756-React.js-INT.book Page I Friday, March 1, 2019 7:15 PM
67756-React.js-INT.book Page II Friday, March 1, 2019 7:15 PM
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
T. PARISOT. – Node.js.
N°13993, 2018, 472 pages.
Éric Sarrion
React.js
67756-React.js-INT.book Page III Friday, March 1, 2019 7:15 PM
67756-React.js-INT.book Page IV Friday, March 1, 2019 7:15 PM
ÉDITIONS EYROLLES
61, bd Saint-Germain
75240 Paris Cedex 05
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
www.editions-eyrolles.com
En application de la loi du 11 mars 1957, il est interdit de reproduire intégralement ou partiellement le présent ouvrage,
sur quelque support que ce soit, sans l’autorisation de l’Éditeur ou du Centre Français d’exploitation du droit de copie,
20, rue des Grands Augustins, 75006 Paris.
© Éditions Eyrolles, 2019, ISBN : 978-2-212-67756-0
67756-React.js-INT.book Page V Friday, March 1, 2019 7:15 PM
Avant-propos .................................................................................. 1
Pourquoi un livre sur React.js ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Guide de lecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Public concerné . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Remerciements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
CHAPITRE 1
JavaScript ES6 ................................................................................. 3
Les variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Utilisation de const . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Utilisation de let . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Mise en forme des chaînes de caractères . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Les fonctions en ES6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Utilisation de paramètres par défaut . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Nouvelle forme de déclaration des fonctions en ES6 . . . . . . . . . . . . . . . . . . . . . . 13
Objet this dans les fonctions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
Les objets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
Déstructurer un objet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
Structurer un objet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Opérateur … sur les objets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
Les tableaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
Déstructurer un tableau . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
Structurer un tableau . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
Opérateur … sur les tableaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
Les classes d’objets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
Création d’une classe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
Héritage de classe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
Les modules. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
Division d’une page HTML en plusieurs fichiers . . . . . . . . . . . . . . . . . . . . . . . . . 39
Intérêt des modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Export de données . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Utilisation du module dans le fichier HTML . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
Import de données . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Utiliser plusieurs modules simultanément . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
Import des modules dans un module global . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
Import des modules directement dans la page HTML . . . . . . . . . . . . . . . . . . . . 48
67756-React.js-INT.book Page VI Friday, March 1, 2019 7:15 PM
React.js
VI
CHAPITRE 2
Hello React .................................................................................... 49
React, c’est quoi ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
CHAPITRE 3
React et JSX................................................................................... 71
Hello React avec JSX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
Utiliser Babel pour interpréter le code JSX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
Créer une arborescence d’éléments avec JSX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
Ajouts d’attributs dans le code JSX. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
Ajout des attributs id et className en JSX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
Ajout de l’attribut style en JSX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
Utilisation d’instructions JavaScript dans le code JSX . . . . . . . . . . . . . . . . . . . . . . . . . 80
Créer un élément JSX avec une fonction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
Créer une fonction qui retourne du code JSX . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
Transmettre des attributs dans un élément JSX . . . . . . . . . . . . . . . . . . . . . . . . . . 84
Créer la liste au moyen de composants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
Créer un élément JSX avec une classe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
Utiliser une fonction ou une classe pour créer les composants en JSX ? . . . . . . . . . . . . . 92
Règles d’écriture du code JSX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
Un seul élément parent peut être retourné . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
Utiliser un fragment avec le composant <React.Fragment> . . . . . . . . . . . . . . . . . . 93
Utiliser des parenthèses en début et en fin du code JSX . . . . . . . . . . . . . . . . . . . . 94
Commentaires dans le code JSX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
Utiliser des expressions conditionnelles dans le code JSX retourné . . . . . . . . . . . . . 96
CHAPITRE 4
Objet state .................................................................................... 99
Utiliser l’objet state pour mettre à jour un composant . . . . . . . . . . . . . . . . . . . . . . . . . 99
Utiliser l’objet props avec l’objet state . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
Arrêter le timer lorsqu’il est arrivé à 0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
Cycle de vie d’un composant . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
Méthodes appelées lorsqu’un composant est créé . . . . . . . . . . . . . . . . . . . . . . . . 107
Méthodes appelées lorsqu’un composant est mis à jour . . . . . . . . . . . . . . . . . . . . 108
Méthodes appelées lorsqu’un composant est détruit . . . . . . . . . . . . . . . . . . . . . . 108
Utilisation du cycle de vie dans un composant HelloReact . . . . . . . . . . . . . . . . . . . . . 109
Utilisation de la méthode componentWillReceiveProps() . . . . . . . . . . . . . . . . . . . . . 113
67756-React.js-INT.book Page VII Friday, March 1, 2019 7:15 PM
CHAPITRE 5
Interactions dans les composants React................................... 119
Gérer le clic sur un bouton . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
CHAPITRE 6
Cas pratique : gérer les éléments d’une liste........................... 133
Insertion d’un élément dans la liste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
Styler les éléments de liste lors du passage de la souris . . . . . . . . . . . . . . . . . . . . . . . . 137
Suppression d’un élément dans la liste (première version) . . . . . . . . . . . . . . . . . . . . . . 138
Suppression d’un élément dans la liste (deuxième version) . . . . . . . . . . . . . . . . . . . . . 140
Modification d’un élément dans la liste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
Prise en compte du double-clic et transformation de l’élément en champ de saisie . . 150
Saisie dans le champ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152
Confirmation de la modification en appuyant sur la touche Entrée . . . . . . . . . . . 156
Agrandissement de la fenêtre. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
CHAPITRE 7
Gérer les formulaires avec React .............................................. 171
Gérer les champs de saisie multilignes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
Composant <TextArea> de base . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
Composant <TextArea> avec focus automatique . . . . . . . . . . . . . . . . . . . . . . . . 174
Composant <TextArea> avec effacement du champ lors de la prise du focus . . . . . 175
Composant <TextArea> avec fonction de traitement . . . . . . . . . . . . . . . . . . . . . 178
Validation du champ lors de la sortie du champ . . . . . . . . . . . . . . . . . . . . . . . 178
Validation du champ grâce à une combinaison de touches . . . . . . . . . . . . . . . . . 180
Validation du champ grâce à un clic sur un bouton de validation . . . . . . . . . . . . 181
Gérer les listes de sélection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186
Créer la liste de sélection avec React . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187
Récupérer la valeur sélectionnée dans la liste de sélection . . . . . . . . . . . . . . . . . . 189
Implémenter une fonction de traitement en attribut . . . . . . . . . . . . . . . . . . . . . . 190
Sélectionner un élément par défaut dans la liste de sélection . . . . . . . . . . . . . . . . 191
Gérer les boutons radio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193
Afficher un groupe de boutons radio à l’aide d’un seul composant React . . . . . . . 193
Afficher un groupe de boutons radio à l’aide de deux composants React . . . . . . . . 195
Présélectionner un bouton radio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
Valider la sélection d’un bouton radio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207
Valider dès qu’un bouton radio est sélectionné . . . . . . . . . . . . . . . . . . . . . . . . 207
67756-React.js-INT.book Page VIII Friday, March 1, 2019 7:15 PM
React.js
VIII
CHAPITRE 8
Utiliser create-react-app pour créer une application React .... 237
Installer l’application create-react-app . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237
Créer un programme React avec la commande create-react-app . . . . . . . . . . . . . . . . . 239
Analyse des fichiers sources de l’application React créée par défaut . . . . . . . . . . . . . . . 243
Créer les fichiers sources de notre application React . . . . . . . . . . . . . . . . . . . . . . . . . 248
Créer une application à destination d’un serveur de production . . . . . . . . . . . . . . . . . 252
Vérifier le type des propriétés utilisées dans les composants . . . . . . . . . . . . . . . . . . . . 255
CHAPITRE 9
Redux........................................................................................... 259
But de Redux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259
Installation de Redux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260
Fonctionnement de Redux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262
Actions dans Redux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262
Les reducers dans Redux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265
Gérer l’état dans le reducer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267
Utilisation des actions avec le reducer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
Prise en compte des changements de l’état dans notre programme . . . . . . . . . . . . . . . 272
Mise en forme du programme dans des modules séparés . . . . . . . . . . . . . . . . . . . . . . 273
Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278
CHAPITRE 10
React et Redux ............................................................................ 279
Associer directement React et Redux pour gérer une liste d’éléments . . . . . . . . . . . . . 279
Vue d’ensemble de l’application côté Redux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280
Vue d’ensemble de l’application côté React . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283
Ajout d’un élément dans la liste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288
Suppression d’un élément dans la liste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289
Modification d’un élément dans la liste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292
Inversion de la liste à l’affichage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
67756-React.js-INT.book Page IX Friday, March 1, 2019 7:15 PM
CHAPITRE 11
Utiliser le module react-redux................................................... 299
Installer le module "react-redux" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
CHAPITRE 12
React Router ............................................................................... 323
Créer les premières routes avec le composant <Route> . . . . . . . . . . . . . . . . . . . . . . . . 325
Afficher la première route qui correspond grâce au composant <Switch> . . . . . . . . . . . 327
Utiliser l’attribut exact dans les routes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 329
Utiliser une route inconnue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331
Afficher un composant dans une route . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333
Utiliser des paramètres dans les routes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335
Utiliser des liens pour afficher les routes grâce au composant <Link> . . . . . . . . . . . . . 340
Utiliser des boutons (à la place des liens) pour naviguer dans les routes . . . . . . . . . . . . 344
Index............................................................................................ 347
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
67756-React.js-INT.book Page X Friday, March 1, 2019 7:15 PM
67756-React.js-INT.book Page 1 Friday, March 1, 2019 7:15 PM
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Avant-propos
Guide de lecture
Le livre est écrit de façon progressive pour le lecteur. Chaque chapitre propose des connais-
sances qui seront utilisées dans les chapitres suivants. Il est donc déconseillé de sauter un cha-
pitre.
Le but final est de comprendre, pas à pas, comment fonctionne React afin de l’utiliser de
façon professionnelle. Pour cela, le livre est organisé en 12 chapitres :
• Chapitre 1 - JavaScript ES6. Découvrir la nouvelle syntaxe de JavaScript utilisée par React.
• Chapitre 2 - Hello React. Introduction à React pour écrire le premier programme.
• Chapitre 3 - React et JSX. Écrire plus facilement le code React à l’aide de la syntaxe JSX.
• Chapitre 4 - Objet state. Comprendre le fonctionnement des états dans les composants React.
• Chapitre 5 - Interactions dans les composants React. Gérer les événements extérieurs,
comme par exemple les clics sur les boutons.
• Chapitre 6 - Cas pratique : gérer les éléments d’une liste. Exemple complet pour interagir
sur les éléments d’une liste (ajout, modification et suppression).
• Chapitre 7 - Gérer les formulaires avec React. Utiliser chaque élément de formulaire pour
les utilisations les plus courantes avec React.
67756-React.js-INT.book Page 2 Friday, March 1, 2019 7:15 PM
React.js
2
• Chapitre 8 - Utiliser create-react-app pour créer une application React. Utiliser un logi-
ciel spécifique qui crée l’architecture de l’application React.
• Chapitre 9 - Redux. Utiliser la bibliothèque Redux pour gérer les états de l’application.
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Public concerné
Développeurs, étudiants, et chefs de projets seront intéressés par la lecture de cet ouvrage.
Remerciements
Nous remercions vivement l’équipe des éditions Eyrolles, ainsi que Gabriel Bieules, Eliza
Gapenne et Jean François Bichet pour leur relecture attentive.
Et merci à vous, cher lecteur, de lire ce livre ! Si celui-ci vous apporte une meilleure compré-
hension du sujet, je vous serai reconnaissant de vos remarques positives que vous pourrez
déposer sur les réseaux sociaux et sites d’achat en ligne !
67756-React.js-INT.book Page 3 Friday, March 1, 2019 7:15 PM
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
1
JavaScript ES6
JavaScript, langage permettant des interactions faciles entre une page web et l’utilisateur, a connu
diverses évolutions ces dernières années, dont la plus significative est celle de la version ES6
(abréviation de « ECMAScript 6 »). Cette nouvelle version concerne particulièrement :
• les variables : déclaration, portée et mise en forme dans les chaînes de caractères ;
• les fonctions : paramètres par défaut, nouvelle forme de déclaration des fonctions ;
• les objets et les tableaux : déstructuration et opérateur… ;
• les classes d’objets : création et dérivation ;
• les promesses : utilisation du processus asynchrone ;
• les modules : pour mieux structurer le code JavaScript.
React utilise de façon intensive ces nouveaux éléments. Ils seront détaillés dans les para-
graphes suivants afin d’écrire et comprendre plus facilement le code React qui sera utilisé
dans ce livre.
Dans la suite du chapitre, nous utiliserons un fichier index.html qui contiendra le code
JavaScript utilisé (au moyen de balises <script>). La structure de ce fichier est la suivante.
67756-React.js-INT.book Page 4 Friday, March 1, 2019 7:15 PM
React.js
4
Fichier index.html
<html>
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
<head>
</head>
<body>
</body>
<script>
</script>
</html>
Les variables
Divers mots-clés ont été ajoutés au langage JavaScript afin de modifier la portée des variables.
Par ailleurs, le mot-clé var permettant de définir une variable locale est toujours actif, mais
ses effets de bord ont été corrigés.
Utilisation de const
Le mot-clé const permet de définir une constante qui, par définition, ne pourra plus être
modifiée. En cas de modification par le programme, une erreur JavaScript est provoquée.
Écrivons le code suivant dans le fichier index.html, dans la partie réservée (balise <script>).
67756-React.js-INT.book Page 5 Friday, March 1, 2019 7:15 PM
JavaScript ES6
5
CHAPITRE 1
Utilisation de const
La modification de la constante nom provoque une erreur que l’on peut voir dans un naviga-
teur, par exemple Chrome (figure 1-1), en utilisant ses outils de développement (touche F12
puis onglet Console).
Figure 1–1
Une constante (définie par const) ne peut plus être affectée une seconde fois. Seule la pre-
mière affectation est autorisée, tandis que les suivantes produisent une erreur nous permettant
de corriger le bug.
Utilisation de let
Le mot-clé let permet de définir de vraies variables locales, qui disparaissent lorsque le bloc
de code dans lequel elles sont définies n’est plus exécuté. De plus, si une variable du même
nom est définie à un niveau supérieur dans le code, cette nouvelle variable définie avec let
n’écrase pas la valeur de la variable de niveau supérieur. Le comportement de let est bien dif-
férent de celui de var.
Voyons sur un exemple la différence entre l’utilisation de var et celle de let. La différence se
voit lorsque le mot-clé var ou let est utilisé dans un bloc de code (entouré par des accolades).
67756-React.js-INT.book Page 6 Friday, March 1, 2019 7:15 PM
React.js
6
if (true) {
var nom = "Martin";
console.log("dans le bloc : " + nom); // "Martin"
}
La variable nom est définie en premier hors du bloc (à la valeur "Sarrion"). Une variable du
même nom est créée dans le bloc, affectée avec une nouvelle valeur ("Martin"). Cette
variable, déclarée à l’aide de var, vient écraser la variable du même nom définie avant le bloc.
Cette variable modifiée est ensuite affichée après le bloc avec la nouvelle valeur.
Figure 1–2
La variable nom définie dans le bloc vient écraser la même variable (du même nom) définie
avant le bloc, car la variable définie dans le bloc n’est pas vue comme étant locale au bloc. En
fait, on n’a pas deux variables, mais une seule en mémoire.
L’effet d’écrasement (de la variable) observé vient du fait que la variable nom définie dans le
bloc à l’aide de var n’est pas locale à ce bloc, mais vient prendre la même place qu’une éven-
tuelle variable du même nom définie précédemment.
L’utilisation du mot-clé let va permettre de créer réellement des variables locales dans un
bloc, sans interférer avec d’autres variables du même nom définies ailleurs.
67756-React.js-INT.book Page 7 Friday, March 1, 2019 7:15 PM
JavaScript ES6
7
CHAPITRE 1
if (true) {
let nom = "Martin";
console.log("dans le bloc : " + nom); // "Martin"
}
On utilise maintenant le mot clé let pour définir la variable dans le bloc. Le résultat va être
très différent du précédent exemple…
Figure 1–3
La variable nom a maintenant une valeur différente dans le bloc et en dehors de celui-ci. C’est
l’utilisation de let (dans le bloc) qui le permet.
On peut également observer la différence entre var et let sur un second exemple. Dans une
boucle for(), une variable déclarée par var ou par let a une incidence sur le comportement
du code JavaScript.
Modifions le fichier index.html pour créer cinq éléments <div> sur lesquels on intercepte le
clic sur chacun d’eux. On utilise tout d’abord le mot-clé var pour définir l’indice i dans la
boucle.
67756-React.js-INT.book Page 8 Friday, March 1, 2019 7:15 PM
React.js
8
Clic sur les éléments <div> créés avec un indice de boucle défini par var dans une boucle for()
for (var i=0; i<5; i++) { // Utilisation de var pour définir l’indice i dans le bloc
var div = document.createElement("div");
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
div.onclick = function() {
console.log("Clic sur Element " + i);
}
}
Ce programme effectue simplement une boucle de 0 à 4 inclus, afin de créer des éléments <div>
sur lesquels on positionne un gestionnaire d’événement onclick. Chaque clic sur un élément
<div> affiche "Clic sur Element " suivi de l’index de l’élément <div> sur lequel on a cliqué.
L’intérêt de ce petit programme ne réside pas dans le code JavaScript permettant de créer les
éléments <div> dans la boucle, mais plutôt dans l’observation de la valeur affichée dans la
console lors des clics sur les différents éléments <div> de la page. Chaque clic sur un élément
produit l’affichage de « Clic sur Element 5 », sachant que cet élément 5 n’est même pas pré-
sent dans la page (figure 1-4) !
Figure 1–4
En effet, la variable i définie par var n’est pas locale au bloc dans lequel elle est définie, et
vient donc écraser son ancienne valeur. A la fin de la boucle, elle finit par atteindre la valeur 5,
ce qui provoque la fin de la boucle. Par la suite, le clic sur n’importe quel élément <div> récu-
père la valeur finale de cette variable, ici la valeur 5.
Un comportement bien différent est visible si l’on utilise le mot-clé let au lieu de var pour
définir la variable i dans la boucle for().
67756-React.js-INT.book Page 9 Friday, March 1, 2019 7:15 PM
JavaScript ES6
9
CHAPITRE 1
Clic sur les éléments <div> créés avec un indice de boucle défini par let dans une boucle for()
for (let i=0; i<5; i++) { // Utilisation de let pour définir i dans le bloc
var div = document.createElement("div");
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
div.onclick = function() {
console.log("Clic sur Element " + i);
}
}
Le programme est identique au précédent, sauf que let a remplacé var pour définir la
variable de boucle i.
Figure 1–5
On voit clairement que la variable i définie par let est maintenant locale à la boucle for().
Et chaque clic indique bien l’élément sur lequel on a cliqué.
React.js
10
var txt = "Le nom est " + nom + ", le prenom est " + prenom;
console.log(txt);
On voit que la ligne permettant de définir la variable txt oblige de fermer chaque chaîne de
caractères avant d’utiliser une variable lors de la concaténation. Le résultat est celui attendu.
Figure 1–6
Une façon plus claire d’écrire peut être utilisée en ES6, sans fermer la chaîne de caractères
lors de la concaténation des variables. On utilise pour cela le guillemet simple inversé (`) pour
définir la chaîne de caractères (au lieu du simple (') ou double (") guillemet traditionnel). Le
programme peut alors s’écrire :
Chaque variable est utilisée dans la chaîne au moyen de ${variable}, sachant que la chaîne
est entourée des guillemets simples inversés. Le résultat est identique au précédent, mais
l’écriture est plus simple.
Le résultat est identique au précédent, et la forme d’écriture est plus concise.
67756-React.js-INT.book Page 11 Friday, March 1, 2019 7:15 PM
JavaScript ES6
11
CHAPITRE 1
concise à écrire.
La fonction log() possède deux paramètres ayant des valeurs par défaut, et nous utilisons la
fonction avec 0, 1 ou 2 arguments afin de voir son comportement (figure 1-7, page suivante).
On voit que lorsqu’un argument n’est pas utilisé, il est remplacé par sa valeur par défaut. Tou-
tefois, comme tous les arguments sont ici facultatifs, il faut utiliser la valeur undefined lors de
l’appel de la fonction si l’argument n’est pas le dernier (les valeurs null ou "" ne sont pas rem-
placées par les valeurs par défaut).
Voici une variante de ce programme en mettant par défaut uniquement le premier paramètre
(ce qui n'est pas conseillé car cela produit des ambiguïtés). Le comportement du programme
est tout autre.
67756-React.js-INT.book Page 12 Friday, March 1, 2019 7:15 PM
React.js
12
Figure 1–7
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
L’ambiguïté porte ici sur l’appel à log("Martin"), pour lequel l’argument "Martin" est consi-
déré comme le premier paramètre de la fonction. Pour lever l’ambiguïté, on est obligé de
mentionner undefined en premier argument lors de l’appel à log(undefined, "Gerard"), ce
qui permet de remplacer l’argument undefined par sa valeur par défaut.
On retiendra donc que les paramètres par défaut s’ajoutent en priorité à la fin de la liste des
paramètres lors de la définition des fonctions.
67756-React.js-INT.book Page 13 Friday, March 1, 2019 7:15 PM
JavaScript ES6
13
CHAPITRE 1
Figure 1–8
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Le mot-clé function a disparu, remplacé par le signe =>. Les paramètres de la fonction
s’écrivent toujours entre parenthèses, tandis que le corps de la fonction est toujours entouré
des accolades de début et de fin.
Si la fonction n’a pas de paramètres, on l’écrit de la façon suivante.
React.js
14
var obj = {
noms : ["Sarrion","Martin","Duval"],
log: function() {
console.log(this.noms);
}
}
obj.log(); // ["Sarrion","Martin","Duval"]
L’objet this représente ici l’objet en cours d’utilisation de la fonction log(), donc l’objet obj.
Figure 1–9
L’objet this permet d’accéder aux noms, qui sont ainsi affichés dans la fonction log().
À présent, écrivons la fonction en tenant compte de la notation ES6.
67756-React.js-INT.book Page 15 Friday, March 1, 2019 7:15 PM
JavaScript ES6
15
CHAPITRE 1
var obj = {
noms : ["Sarrion","Martin","Duval"],
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
log: () => {
console.log(this.noms);
}
}
obj.log();
Il s’agit du même programme écrit en notation ES6. Le résultat devrait être identique...
Pourtant, lors de l’exécution de ce programme, on observe que le résultat est différent du pré-
cédent (figure 1-10) !
Figure 1–10
La propriété noms de l’objet n’est plus accessible (et vaut donc undefined) car this représente
maintenant l’objet JavaScript window, et non plus l’objet obj. Pour s’en assurer, il suffit d’affi-
cher la valeur de this dans la console.
var obj = {
noms : ["Sarrion","Martin","Duval"],
log: () => {
console.log(this); // window
}
}
obj.log();
67756-React.js-INT.book Page 16 Friday, March 1, 2019 7:15 PM
React.js
16
Figure 1–11
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
var obj = {
noms : ["Sarrion","Martin","Duval"],
log : function() {
setTimeout(function() {
console.log(this.noms); // undefined
}, 10); // Exécution du timer au bout de 10 ms
}
}
obj.log();
L’objet this est maintenant utilisé dans la fonction setTimeout(), elle-même définie sur
l’objet window de la page HTML.
L’objet this représente donc l’objet window (c’est-à-dire l’objet qui utilise la fonction
setTimeout(), comme si nous avions écrit dans le code window.setTimeout()).
L’utilisation d’une fonction asynchrone modifie complètement le comportement de notre
programme. La notation ES6 permet de remédier à ce problème.
67756-React.js-INT.book Page 17 Friday, March 1, 2019 7:15 PM
JavaScript ES6
17
CHAPITRE 1
Figure 1–12
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
var obj = {
noms : ["Sarrion","Martin","Duval"],
log : function() {
setTimeout(() => { // Notation ES6
console.log(this.noms);
}, 10);
}
}
obj.log();
Figure 1–13
67756-React.js-INT.book Page 18 Friday, March 1, 2019 7:15 PM
React.js
18
Le résultat est maintenant conforme à nos attentes. La valeur this de l’objet est bien
conservée et transmise dans la fonction asynchrone.
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Les objets
Afin de manipuler plus aisément les objets, ES6 permet de les structurer/déstructurer,
notions qui sont détaillées dans les paragraphes qui suivent.
Déstructurer un objet
Commençons par expliquer la déstructuration d’un objet. Elle permet d’accéder aisément aux
propriétés d’un objet qui nous intéressent, sans nous préoccuper de celles qui ne nous inté-
ressent pas dans l’immédiat.
Prenons l’exemple de l’objet personne, composé des attributs nom, prenom et ville affectés à
cette personne.
Objet personne
var personne = {
nom : "Sarrion",
prenom : "Eric",
ville : "Paris"
}
Afin d’accéder au nom et prenom de la personne, par exemple, on peut écrire en ES6 le code
suivant.
Cela crée deux variables nom et prenom, possédant respectivement la valeur de personne.nom
et personne.prenom. On appelle cela la déstructuration d’un objet, car on accède uniquement
aux propriétés intéressantes (dans cet endroit du programme).
Si seul le nom nous intéresse, on écrira la ligne suivante.
Attention
Même si la notation permettant la déstructuration s’écrit avec des accolades, elle ne crée pas un nouvel
objet, mais uniquement des variables qui correspondent aux valeurs des propriétés de l’objet auxquelles
on accède. Ici on crée donc la variable nom dont la valeur est personne.nom.
67756-React.js-INT.book Page 19 Friday, March 1, 2019 7:15 PM
JavaScript ES6
19
CHAPITRE 1
Cette notation sera particulièrement utile pour transmettre un objet en paramètre, en mon-
trant clairement quelles sont les propriétés de l’objet qui sont finalement utilisées dans la
fonction. Utilisons-la, par exemple, pour transmettre l’objet personne dans la fonction
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
log(personne), sachant que la fonction log() n’utilise que le nom et le prenom de la personne
(on suppose ici que la propriété ville définie pour l’objet personne n’est pas utilisée dans la
fonction log()).
Fonction log() définie en indiquant les propriétés réellement utilisées dans l’objet
transmis en paramètres
var personne = {
nom : "Sarrion",
prenom : "Eric",
ville : "Paris"
}
var log = ({nom, prenom}) => { // Seules les propriétés nom et prenom seront
// utilisées dans la fonction
console.log(`${nom} ${prenom}`);
}
log(personne); // La fonction est appelée avec l’objet en argument
On transmet un objet personne lors de l’appel de la fonction log(), mais seuls le nom et
prenom sont utilisés dans celle-ci. Plutôt que d’indiquer un objet personne en paramètre de la
fonction, on indique les réelles propriétés qui nous intéressent dans la fonction en les écrivant
sous forme déstructurée { nom, prenom } dans la liste des paramètres.
Figure 1–14
React.js
20
var personne = {
nom : "Sarrion",
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
prenom : "Eric",
ville : "Paris"
}
La fonction log() utilise ici le paramètre p correspondant à une personne. Rien n’indique,
dans la liste des paramètres, que ce qui nous intéresse réellement dans le corps de la fonction
est le nom et le prenom. Alors que l’utilisation de la forme déstructurée permet de bien voir les
propriétés réellement utilisées dans l’objet passé en paramètres.
Si la fonction log() possède d’autres paramètres, il suffit de les indiquer dans la liste lors de
sa définition. Supposons que l’on veuille indiquer en paramètre un texte qui sera affiché
devant le nom et le prenom. On écrira alors le code qui suit.
var personne = {
nom : "Sarrion",
prenom : "Eric",
ville : "Paris"
}
Figure 1–15
67756-React.js-INT.book Page 21 Friday, March 1, 2019 7:15 PM
JavaScript ES6
21
CHAPITRE 1
On peut également utiliser des valeurs par défaut pour les paramètres de la fonction. Par
exemple, indiquons que le texte affiché a une valeur par défaut (utilisée si le texte n’est pas
indiqué lors de l’appel de la fonction), et que le nom par défaut est "Sarrion" s’il n’est pas
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
L’objet personne est défini sans la propriété nom, qui aura une valeur par défaut lors de la défi-
nition de la fonction log().
Figure 1–16
Structurer un objet
La structuration d’un objet est le processus inverse de la déstructuration vue précédemment.
Elle permet de créer un objet JavaScript à partir de variables définies dans le code JavaScript.
Cela était déjà possible avec les versions antérieures de JavaScript, mais nécessitait une syn-
taxe plus verbeuse. Pour créer un objet personne à partir des variables nom, prenom et ville
définies dans le programme, on écrivait par exemple ce qui suit.
67756-React.js-INT.book Page 22 Friday, March 1, 2019 7:15 PM
React.js
22
L’objet personne possède les propriétés nom, prenom et ville qui correspondent aux mêmes
noms que les variables définies dans le programme, d’où la redondance entre le nom de la
propriété (à gauche du caractère :) et sa valeur (à droite du caractère :).
Figure 1–17
Plutôt que d’écrire l’objet personne sous la forme propriété : valeur, ES6 permet d’écrire
uniquement le nom de la propriété, sans la valeur, car celle-ci correspondra à la valeur de la
variable ayant le même nom que la propriété. On écrira donc, en utilisant la structuration des
objets ES6, le code suivant.
Définir un objet personne en ES6 à partir des variables nom, prenom et ville
Les propriétés nom, prenom et ville de l’objet personne doivent correspondre à des variables
définies au préalable dans le code JavaScript. Ces variables sont ici définies par le mot-clé var,
mais elles pourraient aussi être définies par les mots-clés let ou const vus précédemment.
67756-React.js-INT.book Page 23 Friday, March 1, 2019 7:15 PM
JavaScript ES6
23
CHAPITRE 1
On peut mixer l’ancienne notation (avec le caractère :) et la nouvelle. Par exemple, en définis-
sant la propriété ville directement dans l’objet personne sans passer par une variable ville.
Le nom et le prenom sont récupérés directement depuis les variables de même nom, tandis que
la propriété ville est directement affectée dans l’objet personne.
Figure 1–18
Si une fonction est définie dans les propriétés de l’objet personne, on peut l’écrire de la façon
suivante.
La fonction log() est définie sur les propriétés de l’objet personne de la même façon que les
autres propriétés de l’objet. Une variable log est recherchée et si elle est trouvée (ce qui est le
cas ici) sa valeur est attachée à cette propriété de l’objet.
67756-React.js-INT.book Page 24 Friday, March 1, 2019 7:15 PM
React.js
24
Figure 1–19
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
La fonction log() peut également être définie de la façon suivante (avec la notation =>) :
var personne = {
nom,
prenom,
log : function() {
console.log(`${this.nom} ${this.prenom}`);
}
};
personne.log();
ES6 permet de supprimer le mot-clé function lors de la définition de la fonction dans l’objet.
On peut alors écrire l’objet de la façon suivante.
67756-React.js-INT.book Page 25 Friday, March 1, 2019 7:15 PM
JavaScript ES6
25
CHAPITRE 1
var personne = {
nom,
prenom,
log() {
console.log(`${this.nom} ${this.prenom}`);
}
};
personne.log();
C’est cette dernière façon de déclarer la fonction dans l’objet qui sera utilisée dans le code
JavaScript, ainsi que lors de la définition des classes en React.
var personne2 = {
personne,
ville
}
console.log(personne2);
// { personne : { nom : "Sarrion", prenom : "Eric" }, ville : "Paris" }
L’objet personne est intégré dans l’objet personne2. Mais le résultat n’est pas forcément celui
attendu (figure 1-20, page suivante).
L’objet personne, intégré dans l’objet personne2, est devenu une propriété personne de ce
nouvel objet. On aurait plutôt voulu que les propriétés de l’objet personne s’intègrent directe-
ment dans le nouvel objet, de façon à ce que celui-ci ait donc les propriétés nom, prenom et
ville (au lieu des propriétés personne et ville comme c’est le cas actuellement).
L’opérateur … va nous aider à réaliser l’éclatement des propriétés de l’objet personne en les
intégrant directement dans le nouvel objet. Pour cela, il suffit d’écrire le code qui suit.
67756-React.js-INT.book Page 26 Friday, March 1, 2019 7:15 PM
React.js
26
Figure 1–20
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Créer un nouvel objet à partir d’un objet existant en utilisant l’opérateur ...
var personne2 = {
...personne, // Objet personne éclaté
ville
}
console.log(personne2);
La seule différence avec le programme précédent est l’opérateur … utilisé pour éclater les pro-
priétés de l’objet personne en les intégrant directement dans le nouvel objet.
L’opérateur … ne peut s’utiliser que dans un objet JavaScript, comme on peut le voir dans
l’exemple précédent.
Figure 1–21
67756-React.js-INT.book Page 27 Friday, March 1, 2019 7:15 PM
JavaScript ES6
27
CHAPITRE 1
L’objet personne a été éclaté et intégré dans le nouvel objet avec ses propriétés directement
attachées au nouvel objet.
Plusieurs opérateurs ... peuvent figurer dans la définition d’un objet. Si lors de l’éclatement,
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
des propriétés portent le même nom dans différents objets éclatés, une seule propriété ayant
ce nom est insérée dans le nouvel objet (la dernière rencontrée).
Par exemple, on peut créer un nouvel objet à partir des objets personne et place (l’objet
place permettant de définir la ville et le code postal (propriété cp)).
var personne2 = {
...personne, // Objet personne éclaté
...place // Objet place éclaté
}
console.log(personne2);
Figure 1–22
Les deux objets (personne et place) ont été éclatés, et leurs propriétés sont attachées à l’objet
personne2 ainsi créé.
Les tableaux
Nous venons de voir qu’il est possible de déstructurer ou structurer un objet. Ce type d’opéra-
tion peut également être effectué avec les tableaux.
67756-React.js-INT.book Page 28 Friday, March 1, 2019 7:15 PM
React.js
28
Déstructurer un tableau
La déstructuration d’un tableau va permettre de récupérer des parties du tableau (comme on
le ferait pour certaines propriétés d’un objet).
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
var [nom1, nom2, nom3] = noms; // nom1 = noms[0], nom2 = noms[1], nom3 = noms[2]
Les éléments du tableau noms sont récupérés dans les variables nom1, nom2 et nom3, dans
l’ordre où les éléments sont inscrits dans le tableau.
Figure 1–23
Si l’on souhaite uniquement récupérer le deuxième élément du tableau, on écrira le code suivant.
console.log(nom2); // "Martin"
console.log(nom3); // "Duval"
67756-React.js-INT.book Page 29 Friday, March 1, 2019 7:15 PM
JavaScript ES6
29
CHAPITRE 1
Les index non récupérés dans le tableau sont remplacés par des virgules.
Structurer un tableau
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
La structuration d’un tableau s’effectue principalement avec l’opérateur … détaillé dans les
paragraphes qui suivent.
On indique ici de créer les deux variables nom1 et suite, toutes deux extraites du tableau noms.
La variable nom1 correspond au premier élément du tableau, tandis que la variable suite cor-
respond au reste du tableau (après le premier élément déjà extrait).
Figure 1–24
Pour récupérer les éléments du tableau à partir du troisième élément (au lieu du deuxième
comme précédemment), il suffit d’insérer une virgule supplémentaire lors de la déstructura-
tion du tableau.
67756-React.js-INT.book Page 30 Friday, March 1, 2019 7:15 PM
React.js
30
console.log(suite); // ["Duval"]
La classe Personne ici définie est pour l’instant vide, elle sera enrichie par la suite. L’objet
personne de classe Personne est créé au moyen de l’opérateur new, suivi du nom de la classe.
Ici, on aurait également pu écrire new Personne; car pour l’instant, on ne transmet aucun
argument lors de la création de l’objet.
L’objet personne affiché est de classe Personne. Il est vide comme on peut s’y attendre, vu que
la classe Personne l’est également pour l’instant (figure 1-25).
Une personne possède un nom et un prenom. Ajoutons ces attributs dans la classe Personne
afin que les objets correspondants les utilisent.
Pour définir des attributs dans une classe, il faut utiliser une méthode qui est appelée dès
qu’un objet de cette classe est instancié (c’est-à-dire créé au moyen de l’opérateur new). Dans
ES6, cette méthode de construction s’appelle constructor() et aura en paramètres les élé-
ments qui seront transmis lors de la création de l’objet par new. La méthode constructor()
est présente dans toutes les classes que l’on crée et s’appelle le constructeur de la classe.
67756-React.js-INT.book Page 31 Friday, March 1, 2019 7:15 PM
JavaScript ES6
31
CHAPITRE 1
Figure 1–25
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
class Personne {
constructor(nom, prenom) {
this.nom = nom;
this.prenom = prenom;
}
}
La méthode constructor() possède désormais les paramètres qui seront utilisés lors de la
création des objets de la classe Personne. Afin de les conserver en tant qu’attributs dans la
classe (et pouvoir les utiliser dans des méthodes qui seront définies dans cette classe), on les
mémorise dans l’objet this (au moyen de this.nom et this.prenom).
Remarquez que lors de la construction des objets par new, il faut maintenant indiquer en
arguments les valeurs des paramètres utilisés, qui seront transmis dans la méthode
constructor(). Si la méthode constructor() utilise des paramètres par défaut, les argu-
ments correspondants peuvent être absents lors de la création des objets associés.
On voit ici le contenu des deux objets créés, avec, entre accolades, les attributs créés au moyen
de this dans le constructeur (figure 1-26).
Une classe est souvent enrichie au moyen de méthodes, qui seront ensuite utilisées par les
objets de cette classe. Par exemple, on peut créer une fonction log() dans la classe Personne
qui permettra de visualiser le nom et prenom des objets de cette classe.
67756-React.js-INT.book Page 32 Friday, March 1, 2019 7:15 PM
React.js
32
Figure 1–26
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
class Personne {
constructor(nom, prenom) {
this.nom = nom;
this.prenom = prenom;
}
log() {
console.log(`Nom : ${this.nom}, Prénom : ${this.prenom}`);
}
}
La méthode log() est définie dans la classe, sans indiquer le mot-clé function (sinon, une
erreur de syntaxe se produirait), mais en utilisant des parenthèses (ici elles sont vides car il n’y
a pas de paramètres à indiquer lors de l’appel de la méthode). Le corps de la fonction suit,
entouré des accolades permettant d’écrire le code correspondant.
L’appel de la méthode log() s’effectue ensuite sur chacun des objets (personne et personne2)
pour lesquels on souhaite l’utiliser.
67756-React.js-INT.book Page 33 Friday, March 1, 2019 7:15 PM
JavaScript ES6
33
CHAPITRE 1
Figure 1–27
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Héritage de classe
L’héritage de classe permet de créer une nouvelle classe à partir d’une classe déjà existante.
On dit que la nouvelle classe est dérivée (héritée) de la première. Il est ainsi possible d’enri-
chir (améliorer) une classe existante sans avoir à modifier son code interne. On peut alors
réutiliser des morceaux de code existants (c’est-à-dire utiliser d’autres classes qui ont déjà été
écrites et qui fonctionnent correctement).
Pour illustrer cela, on souhaite créer une nouvelle classe, appelée Homme, dérivée de la classe
Personne écrite précédemment. On peut de la même façon créer la classe Femme, également
dérivée de la classe Personne, mais qui permet de traiter les personnes de sexe féminin.
Pour indiquer qu’une classe dérive d’une autre classe, on utilise le mot-clé extends. Ainsi,
pour indiquer que la classe Homme dérive de la classe Personne, on écrira ce qui suit.
React.js
34
class Personne {
constructor(nom, prenom) {
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
this.nom = nom;
this.prenom = prenom;
}
log() {
console.log(`Nom : ${this.nom}, Prénom : ${this.prenom}`);
}
}
La classe Homme possède elle aussi un constructeur, dans lequel on insère un nouvel attribut sexe
correspondant au sexe de la personne. Les deux personnes créées le sont maintenant au moyen
de new Homme() au lieu de new Personne(). De plus, l’appel de la méthode log() définie dans
la classe Personne peut s’effectuer sur les objets d’une classe dérivée, ici la classe Homme.
Exécutons le programme précédent :
Figure 1–28
67756-React.js-INT.book Page 35 Friday, March 1, 2019 7:15 PM
JavaScript ES6
35
CHAPITRE 1
Une erreur se produit indiquant qu’il faut appeler le super constructeur dans la classe dérivée.
En effet, pour créer un objet Homme, il faut s’appuyer sur le processus de construction d’un
objet Personne (sinon cela ne sert à rien d’indiquer que la classe Homme dérive de la classe
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Personne). Par conséquent, dans le constructeur de la classe Homme (classe dérivée), il faut
également appeler le constructeur de la classe Personne (classe parente), ce qui se fait en uti-
lisant la méthode super() à laquelle on transmet les arguments nom et prenom qui définissent
un objet Personne.
class Personne {
constructor(nom, prenom) {
this.nom = nom;
this.prenom = prenom;
}
log() {
console.log(`Nom : ${this.nom}, Prénom : ${this.prenom}`);
}
}
React.js
36
Figure 1–29
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
class Personne {
constructor(nom, prenom) {
this.nom = nom;
this.prenom = prenom;
}
log() {
console.log(`Nom : ${this.nom}, Prénom : ${this.prenom}`);
}
}
JavaScript ES6
37
CHAPITRE 1
Les objets de classe Personne utiliseront la méthode log() définie dans la classe Personne,
tandis que les objets de classe Homme utiliseront la méthode log() définie dans la classe Homme.
Figure 1–30
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
La méthode log() définie dans la classe parente Personne n’est plus appelée, car sur les objets
de classe Homme, on utilise en priorité la méthode log() définie sur les objets de cette classe.
La question à se poser est maintenant la suivante : comment peut-on malgré tout appeler la
méthode log() définie dans la classe Personne depuis la classe Homme, sachant que la méthode
porte le même nom dans les deux classes ?
Cela est possible en appelant la méthode log() située dans la classe parente, au moyen du
mot-clé super. L’instruction super.log() permet donc d’appeler la méthode log() définie
dans la classe parente.
Appel des méthodes log() définies dans une classe dérivée et une classe parente
class Personne {
constructor(nom, prenom) {
this.nom = nom;
this.prenom = prenom;
}
log() {
console.log(`Nom : ${this.nom}, Prénom : ${this.prenom}`);
}
}
React.js
38
log() {
super.log(); // Appel de la méthode log() définie dans la classe parente
console.log("C'est un homme !");
}
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Figure 1–31
Les deux méthodes log() définies dans les deux classes sont maintenant appelées.
Les modules
ES6 permet de définir des modules, c’est-à-dire des fichiers JavaScript qui permettent de
diviser un programme JavaScript en fichiers autonomes, inclus dans la page HTML ou dans
d’autres modules.
Un module permet de définir des constantes, des variables, des fonctions ou des classes (en
fait, tout type de donnée) qui sont par défaut privées pour le module (les autres modules n’y
ont pas accès, à moins de les y autoriser).
67756-React.js-INT.book Page 39 Friday, March 1, 2019 7:15 PM
JavaScript ES6
39
CHAPITRE 1
Pour bien comprendre l’apport des modules ES6 par rapport aux fichiers JavaScript tradition-
nels, divisons le fichier HTML précédent en divers fichiers utilisés ensemble.
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
class Personne {
constructor(nom, prenom) {
this.nom = nom;
this.prenom = prenom;
}
log() {
console.log(`Nom : ${this.nom}, Prénom : ${this.prenom}`);
}
}
La classe Personne peut être utilisée dans un fichier HTML en incluant le fichier
personne.js au moyen d’une balise <script> classique.
<html>
<head>
<meta charset="utf-8">
<script src="./personne.js"></script>
</head>
<script>
</script>
</html>
Une fois le fichier contenant la définition de la classe Personne inclus dans la page HTML,
on peut accéder à la classe et à ses fonctionnalités.
67756-React.js-INT.book Page 40 Friday, March 1, 2019 7:15 PM
React.js
40
Figure 1–32
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
La classe Personne est accessible ainsi que la fonction log() définie dans la classe.
Faisons la même chose avec la classe Homme, en la définissant dans un fichier homme.js qui
sera lui aussi inclus dans la page HTML.
Pour inclure ce fichier dans la page HTML, il est obligatoire d’inclure au préalable le fichier
personne.js qui définit la classe Personne (sinon la classe Personne, utilisée par la classe
Homme, est inconnue).
<html>
<head>
67756-React.js-INT.book Page 41 Friday, March 1, 2019 7:15 PM
JavaScript ES6
41
CHAPITRE 1
<meta charset="utf-8">
<script src="./personne.js"></script>
<script src="./homme.js"></script>
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
</head>
<script>
</script>
</html>
Les deux fichiers JavaScript incluant les classes Personne et Homme sont inclus, ce qui permet
d’utiliser ces deux classes dans le script de la page HTML.
Figure 1–33
L’objet de classe Personne est affiché, puis l’objet de classe Homme. Chaque classe utilise la
méthode log() définie dans sa classe.
67756-React.js-INT.book Page 42 Friday, March 1, 2019 7:15 PM
React.js
42
Cette approche, bien que fonctionnelle, présente un inconvénient majeur (dans le cadre d’un
développement nécessitant beaucoup de fichiers). En effet, lors de l’inclusion des fichiers
JavaScript nécessaires dans le fichier principal :
• l’ordre d’inclusion doit être connu : il faut inclure personne.js avant homme.js, sinon cela
ne fonctionne pas ;
• les dépendances entre fichiers doivent être connues : le fichier homme.js nécessite
d’inclure le fichier personne.js, sinon la classe Homme ne peut pas être créée à partir de la
classe Personne.
On voit donc que le fait de disposer de fichiers a priori indépendants tels que les fichiers
personne.js et homme.js nécessite des informations afin de savoir comment les utiliser.
Le but des modules ES6 est d’aider à utiliser ces fichiers (ici, personne.js et homme.js) sans
avoir à connaître ces informations. En effet, ces dernières seront insérées sous une certaine
forme dans le fichier lui-même, qui devient ainsi un module.
C’est le rôle de l’export et de l’import des données, notions que nous détaillons dans les para-
graphes qui suivent.
Export de données
Dans chaque module (en fait, un fichier contenant du code JavaScript), on décide quelles
sont les données que l’on souhaite rendre visibles à l’extérieur (pour d’autres modules ou pour
une page HTML). On utilise pour cela le nouveau mot-clé JavaScript export, qui permet
d’exporter une ou plusieurs données vers l’extérieur.
Dans notre exemple, on souhaite exporter les classes Personne et Homme de façon à les rendre
accessibles à l’extérieur. On ajoute alors le mot-clé export dans chacun des deux fichiers (qui
deviennent ainsi des modules).
Module personne.js
class Personne {
constructor(nom, prenom) {
this.nom = nom;
this.prenom = prenom;
}
log() {
console.log(`Nom : ${this.nom}, Prénom : ${this.prenom}`);
}
}
export { Personne };
67756-React.js-INT.book Page 43 Friday, March 1, 2019 7:15 PM
JavaScript ES6
43
CHAPITRE 1
Ainsi, pour transformer un fichier JavaScript en module, il suffit de lui ajouter le mot-clé
export précisant les données exportées, séparées par des virgules si plusieurs données sont à
exporter, et entourées d’accolades.
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Si une seule donnée est exportée dans le module, on peut écrire également la ligne suivante.
L’instruction export default ne s’utilise que si une seule donnée est exportée dans le
module. Dans les autres cas, on utilise la première syntaxe avec les accolades.
<html>
<head>
<meta charset="utf-8">
</head>
<script type="module">
</script>
</html>
Le fichier JavaScript du module est inclus au moyen de l’instruction import. Pour que cette
instruction soit comprise par le navigateur, il faut qu’elle soit insérée dans une balise <script
type="module">, sinon l’instruction import n’est pas reconnue.
Exécutons cette page HTML dans le navigateur (figure 1-34).
Le message d’erreur indique un problème d’accès au fichier du module. En effet, les fichiers
associés à des modules ne sont accessibles que par le protocole HTTP, et ici c’est pour l’ins-
tant le protocole file qui est utilisé dans l’URL du navigateur. D’où le message d’erreur...
67756-React.js-INT.book Page 44 Friday, March 1, 2019 7:15 PM
React.js
44
Figure 1–34
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
L’erreur peut facilement être corrigée en changeant le protocole d’accès à l’URL du fichier
index.html. Il suffit d’installer un serveur web (si ce n’est pas déjà fait) et d’accéder au fichier
index.html depuis une URL HTTP, par exemple http://localhost/react, en supposant que le fichier
index.html et les différents modules utilisés soient déposés dans le répertoire react du serveur.
Lorsque c’est fait, la page HTML s’affiche correctement (avec les informations dans la
console).
Figure 1–35
67756-React.js-INT.book Page 45 Friday, March 1, 2019 7:15 PM
JavaScript ES6
45
CHAPITRE 1
Lors de l’utilisation des modules ES6, les URL HTTP sont obligatoires pour accéder à la
page HTML.
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Import de données
Dans l’exemple précédent, nous avons utilisé l’instruction import afin que notre script puisse
utiliser les données du module importé. Les données utilisées dans le script (et importées
depuis le module) sont précisées dans l’instruction import.
On ne peut importer que des données qui ont été précédemment exportées, sinon une erreur
se produit. Par exemple, il est impossible d’importer la classe Personne si cette classe n’a pas
été exportée dans le module où elle est définie.
export { Personne };
Si d’autres données sont à exporter dans ce module, il faut les indiquer à la suite, entre acco-
lades et séparées par une virgule.
Si d’autres données sont à importer depuis ce module, il faut les indiquer à la suite, entre
accolades et séparées par une virgule.
Dans le cas où une seule donnée est à exporter dans un module, on peut l’exporter au moyen
de l’instruction export default.
Une donnée exportée par export default doit alors être importée comme ceci.
Les accolades ne sont plus nécessaires (et provoquent une erreur si vous les ajoutez).
Remarquons que les instructions import et export peuvent s’utiliser dans les fichiers décri-
vant les modules, mais également dans des modules qui les utilisent, ou dans des fichiers
HTML au moyen de la balise <script type="module">.
67756-React.js-INT.book Page 46 Friday, March 1, 2019 7:15 PM
React.js
46
Module personne.js
class Personne {
constructor(nom, prenom) {
this.nom = nom;
this.prenom = prenom;
}
log() {
console.log(`Nom : ${this.nom}, Prénom : ${this.prenom}`);
}
}
Module homme.js
Une fois ces deux modules définis, ils peuvent être utilisés de deux façons :
• intégration des modules dans un module global, puis utilisation de ce module global dans
la page HTML ;
• utilisation directe des deux modules dans la page HTML.
Voyons maintenant ces deux possibilités.
JavaScript ES6
47
CHAPITRE 1
Module index.js
Fichier index.html
<html>
<head>
<meta charset="utf-8">
</head>
</html>
Remarque
L’utilisation de la balise <script type="module"> permet de préciser que le fichier index.js utilise
le concept de module. Si l’attribut type n’a pas la valeur "module", une erreur se produit.
Figure 1–36
67756-React.js-INT.book Page 48 Friday, March 1, 2019 7:15 PM
React.js
48
Les deux objets Personne et Homme sont correctement affichés dans la console.
Plutôt que de passer par un module intermédiaire (ici, index.js), on peut utiliser les modules
personne.js et homme.js directement dans la page HTML. Cette solution est plus rapide à
écrire (un fichier en moins), mais moins fréquemment utilisée que la précédente.
Son écriture est des plus simples : le contenu du fichier index.js précédent se retrouve direc-
tement dans un script de la page HTML. Le script devra avoir l’attribut type="module" pour
accepter les instructions import des différents modules.
Fichier index.html
<html>
<head>
<meta charset="utf-8">
</head>
<script type="module">
</script>
</html>
Les instructions import figurent directement dans le code JavaScript de la page HTML, à
condition que ce code JavaScript ait été déclaré avec l’attribut type="module".
67756-React.js-INT.book Page 49 Friday, March 1, 2019 7:15 PM
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
2
Hello React
Dans ce chapitre, nous allons enfin commencer à écrire du code React ! L’objectif sera ici de
vous faire découvrir les bases de React afin de comprendre comment celui-ci fonctionne.
React.js
50
<html>
<head>
<script crossorigin
src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin
src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
</head>
<body>
<div id="app"></div>
</body>
<script>
</script>
</html>
67756-React.js-INT.book Page 51 Friday, March 1, 2019 7:15 PM
Hello React
51
CHAPITRE 2
La page HTML inclut les deux bibliothèques React et ReactDOM en mode développement
(ici, la version 16). La balise <head> contient une copie du code proposé sur la page du site
reactjs.org citée précédemment.
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
La partie <body> contient un élément <div> possédant l’id "app". Cet élément <div> servira à
contenir les éléments HTML affichés dans la page par le code React, et c’est pour cela que
son contenu est vide (seul l’id est utile afin de pouvoir y accéder par JavaScript).
Le code React est créé en JavaScript, d’où la balise <script> en fin de page qui permettra de
l’insérer. Le code React est ici inséré directement depuis la page HTML, mais il aurait pu
être écrit dans un fichier JavaScript séparé, lui-même inclus dans la page HTML au moyen
d’une autre balise <script>.
Remarquez que cette page HTML affiche une page vierge dans le navigateur, car pour l’ins-
tant aucun élément HTML n’est affiché (hormis l’élément <div> sans contenu), et aucun
code JavaScript n’est exécuté afin de créer du contenu HTML.
Vous pouvez visualiser cette page dans un navigateur, soit en déposant le fichier HTML dans
un navigateur (enregistrez le fichier sur votre ordinateur et depuis l’explorateur de fichiers,
faites-le glisser dans le navigateur), soit en installant un serveur sur votre machine. Pour l’ins-
tant, nous retenons la première solution.
Figure 2–1
La page affichée est effectivement vierge. La fenêtre située en bas de page correspond aux
outils de développement disponibles sous Chrome en appuyant sur la touche F12 du clavier.
67756-React.js-INT.book Page 52 Friday, March 1, 2019 7:15 PM
React.js
52
L’onglet Elements permet de visualiser les éléments HTML affichés dans la page, tandis que
l’onglet Console permet de voir les éventuels messages affichés (soit d’erreurs Javascript, soit
affichés par notre programme au moyen de console.log()).
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
L’onglet React correspond à l’extension React Developper Tools que l’on aura préalablement
installée sous Chrome. Elle permet de visualiser les composants créés par React et sera tou-
jours utile pour la suite.
Il reste maintenant à produire un affichage dans cette page. Pour cela, on écrit le code React
en JavaScript dans la partie <script> réservée à cet usage (en bas du fichier index.html).
Le code React suivant va permettre de créer un paragraphe HTML (balise <p>) et de l’insérer
dans l’élément <div> créé à cet effet dans la page (celui dont l’id est "app").
L’inclusion des fichiers React dans la partie <head> de la page permet d’avoir accès aux fonc-
tionnalités de React, en particulier les objets React et ReactDOM utilisés ici.
La méthode React.createElement(élément, attributs, enfants) permet de créer un
objet React correspondant à un élément HTML (ici, un élément <p>, indiqué en premier
paramètre), en spécifiant ses attributs sous forme d’objet en second paramètre (ici, il n’y en a
aucun donc on indique null), puis ses enfants en troisième paramètre (ici, le texte du para-
graphe).
La méthode React.createElement() crée un objet JavaScript utilisable par React, mais cet
objet doit s’afficher dans la page HTML pour être visible, ce que permet l’appel à la méthode
ReactDOM.render(objet React, élément DOM où afficher l'objet React). L’élément
DOM où doit s’afficher l’objet React est récupéré par l’instruction JavaScript
document.getElementById("app"), d’où l’utilité d’avoir spécifié un id à cet élément pour
pouvoir y accéder ici.
Le paragraphe Hello React est affiché dans la page. La fenêtre de l’onglet Console des outils
de développement de Chrome affiche le résultat de console.log(p), p étant l’objet React
créé par React.createElement() (voir figure 2-2).
L’onglet React permet de visualiser les éléments créés par React (voir figure 2-3).
On affiche ici un simple élément React. Cette rubrique sera plus intéressante lorsque les élé-
ments créés seront plus nombreux...
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Figure 2–3
Figure 2–2
67756-React.js-INT.book Page 53 Friday, March 1, 2019 7:15 PM
CHAPITRE 2
Hello React
53
67756-React.js-INT.book Page 54 Friday, March 1, 2019 7:15 PM
React.js
54
par exemple lui affecter un id, un style, voire une classe CSS.
Le second paramètre de la méthode React.createElement() permet de préciser, sous forme
d’objet JSON, les attributs que l’on souhaite affecter à l’élément.
Commençons par ajouter un attribut id au paragraphe précédent.
Figure 2–4
La valeur de l’attribut id a été positionnée dans l’objet React associé au paragraphe (objet
créé par React.createElement()), dans sa propriété props. Cette propriété est ajoutée par
React à tous les éléments React créés par React.createElement().
Hello React
55
CHAPITRE 2
Modifions maintenant le style de l’élément en lui affectant la couleur rouge (propriété CSS
color), et un fond noir (propriété CSS background-color). On utilise pour cela l’attribut
HTML style.
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
var p = React.createElement("p",
{ id : "id1", style : { color:"red", backgroundColor:"black" } },
"Hello React");
console.log(p);
ReactDOM.render(p, document.getElementById("app"));
L’attribut style est décrit sous forme d’objet JSON, et non pas sous forme de chaîne de
caractères comme cela serait le cas si l’on avait écrit directement le paragraphe en code
HTML. N’oublions pas que les éléments créés par React le sont grâce à du code JavaScript,
ce qui implique de respecter la syntaxe de ce langage.
Une propriété CSS composée de plusieurs mots, telle que background-color, peut s’utiliser
en remplaçant chaque tiret par la majuscule du mot qui suit (donc ici, backgroundColor) ou
en l’entourant de guillemets (donc ici, "background-color").
Figure 2–5
React.js
56
La fenêtre des outils de développement permet de voir l’objet React associé à cet élément, en
particulier l’objet style créé par React dans l’objet props.
L’onglet React affiche l’élément React sous une autre forme.
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Figure 2–6
L’intérêt de l’onglet React est qu’il permet de voir l’architecture des éléments créés par React
sans pour cela utiliser des affichages par console.log().
Un cas particulier d’attribut est lorsqu’on utilise l’attribut class. En effet, cet attribut ne peut
pas s’utiliser directement dans le code JavaScript car il serait interprété comme une déclara-
tion de classe JavaScript. React permet de le remplacer par l’attribut className comme on
peut le voir dans le code suivant.
<html>
<head>
<script crossorigin
src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin
src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
67756-React.js-INT.book Page 57 Friday, March 1, 2019 7:15 PM
Hello React
57
CHAPITRE 2
<style type="text/css">
.red { /* Définition de la classe CSS red */
color : red;
}
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
</style>
</head>
<body>
<div id="app"></div>
</body>
<script>
</script>
</html>
React.js
58
Les cinq enfants sont créés par la même méthode que l’élément parent (c’est-à-dire par
React.createElement()) et sont insérés dans le dernier paramètre de la méthode
React.createElement(), les uns à la suite des autres (séparés par une virgule). Cette méthode
peut donc comporter un nombre quelconque d’arguments, les enfants de l’élément à créer
étant considérés comme figurant à partir de la troisième position de la liste des arguments (ou
peuvent être mis dans un tableau comme on va le voir ci-après).
Chacun des enfants peut également posséder lui-même des enfants, ce qui signifie qu’au lieu
d’avoir un élément texte comme ici ("Element1", par exemple), on pourrait avoir l’instruction
React.createElement(). On voit donc que de cette façon, on peut construire n’importe quel
fragment HTML (figure 2-8).
Les cinq enfants de l’élément React sont mis dans la propriété children de l’objet props
associé à cet élément React, chacun de ces enfants étant lui-même un élément React.
En sélectionnant l’onglet React dans la fenêtre, on peut voir l’arborescence des éléments React
ainsi créés (figure 2-9).
En cliquant sur chacun des éléments dans la partie gauche de la fenêtre, on peut voir ses pro-
priétés regroupées dans l’objet props.
Les enfants d’un élément peuvent s’insérer dans la liste des paramètres de la méthode
React.createElement(), en commençant à partir du troisième, comme on l’a fait précédem-
ment. Il est également possible de les indiquer sous forme de tableau, toujours dans le troi-
sième paramètre de la méthode React.createElement().
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Figure 2–9
Figure 2–8
67756-React.js-INT.book Page 59 Friday, March 1, 2019 7:15 PM
CHAPITRE 2
Hello React
59
67756-React.js-INT.book Page 60 Friday, March 1, 2019 7:15 PM
React.js
60
Les enfants <li> de l’élément <ul> sont maintenant regroupés dans un tableau d’éléments
correspondant au troisième paramètre de la méthode React.createElement().
Même si le programme est fonctionnel, un message d’erreur s’affiche dans l’onglet React.
Nous allons voir comment éliminer ce message d’erreur dans la section suivante.
Par ailleurs, le fait de pouvoir regrouper les enfants d’un élément dans un tableau va nous
servir dans la section qui suit.
Les textes des éléments de liste sont insérés dans un tableau elems. Ce tableau est parcouru
au moyen de la méthode map() (méthode JavaScript définie sur la classe Array). La méthode
map() utilise une fonction de callback (définie en paramètre) qui est appelée pour chaque élé-
ment du tableau. Pour chaque appel de cette fonction de callback, l’élément du tableau et son
index dans le tableau sont transmis en paramètres à la fonction de callback (elem et index).
Comme la méthode map() retourne un tableau d’éléments React <li>, celui-ci est transmis
comme liste des enfants de l’élément <ul>.
67756-React.js-INT.book Page 61 Friday, March 1, 2019 7:15 PM
Hello React
61
CHAPITRE 2
Figure 2–10
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Les éléments de liste sont effectivement insérés dans l’élément <ul>. Toutefois, l’onglet React
affiche une erreur (croix rouge accompagné du chiffre 1). Un clic sur cette croix affiche un
message qui explique l’erreur : « Each child in an array or iterator should have a unique "key"
prop. », ce qui signifie qu’il faut que chaque élément inséré au moyen d’un tableau ou d’une
boucle possède une propriété key unique.
Ce message d’erreur est le même que celui qui s’affichait dans l’exemple précédent.
Pour supprimer le message d’erreur de React, il suffit d’attribuer une propriété key ayant une
valeur différente à chacun des éléments <li> insérés.
La valeur attribuée à la propriété key est celle de l’index de l’élément dans la liste, qui est for-
cément unique comme demandé.
67756-React.js-INT.book Page 62 Friday, March 1, 2019 7:15 PM
React.js
62
plus condensée.
La fonction listeElements() crée la liste des éléments (<ul> et ses <li> enfants). Elle
retourne un élément React parent (associé au <ul>), lui-même composé d’enfants React
(associés aux <li>).
67756-React.js-INT.book Page 63 Friday, March 1, 2019 7:15 PM
Hello React
63
CHAPITRE 2
Cette fonction est appelée automatiquement par React car elle figure en premier argument de
l’appel à React.createElement(listeElements). Remarquez que la fonction listeElements()
n’est pas appelée par notre programme (on n’a pas mis les parenthèses () à la suite), c’est l’instruc-
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Dans l’onglet React, on voit qu’un élément React du même nom que la fonction
listeElements() a été créé par React. Toutefois, cet élément est simplement un objet en
mémoire utilisé par React, il n’est pas visible dans le code HTML de la page.
React.js
64
Hello React
65
CHAPITRE 2
D’autres valeurs peuvent être transmises dans les attributs, qui seront récupérées de la même
façon dans l’objet props transmis par React en paramètre.
En ES6, on avait vu le principe de déstructuration d’un objet. Comme dans notre fonction
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
listeElements(props) on n’utilise que la propriété elems de l’objet props, il est plus limpide
d’écrire le programme en utilisant cette syntaxe.
L’objet props n’existant plus dans la liste des paramètres de la fonction listeElements(), on
accède directement à la propriété elems transmise dans l’objet props.
Et plutôt que d’utiliser le mot-clé function pour définir la fonction, on peut aussi utiliser la
syntaxe ES6 avec les caractères =>.
React.js
66
Figure 2–12
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Comme on l’a vu, cette méthode peut être utilisée dans une fonction qui retourne l’élément
React parent, mais peut également être utilisée dans une classe JavaScript qui dérive d’une
classe nommée React.Component définie dans React. C’est cette nouvelle façon de procéder
que l’on va expliquer maintenant, en créant une liste d’éléments comme précédemment.
Hello React
67
CHAPITRE 2
Figure 2–13
On voit dans l’onglet React que la liste comporte bien les éléments HTML désirés (<ul> et
<li>),
mais également un élément React ayant le même nom que la classe ListeElements.
67756-React.js-INT.book Page 68 Friday, March 1, 2019 7:15 PM
React.js
68
Modifions le programme afin que chaque élément de liste soit écrit dans une couleur trans-
mise lors de la création de la liste (dans la liste des attributs). Il suffit d’indiquer ce style lors
de la création de l’élément ListeElements.
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
L’attribut style est ajouté dans les attributs transmis lors de la création de l’objet de classe
ListeElements via l’objet props, et donc récupéré dans la classe par this.props.style.
Toutefois, le résultat n’est pas celui espéré (figure 2-14).
L’erreur est visible dans l’onglet Console de la fenêtre des outils de développement de Chrome.
Il y est expliqué que l’on ne peut pas accéder à la propriété props de l’objet this (dans l’ins-
truction this.props.style écrite sur la ligne correspondante). Pourtant, il n’y a pas d’erreur
lorsque l’on essaye d’accéder à this.props.elems écrite sur la ligne précédente...
Pourquoi peut-on accéder à this.props.elems et pas à this.props.style ? La réponse est
que l’instruction this.props.style est utilisée dans une fonction de callback, ce qui fait
perdre la variable this qui n’est plus la même dans la fonction de callback et à l’extérieur de
celle-ci. L’objet this utilisé dans this.props.elems n’est pas le même que celui utilisé dans
this.props.style.
On avait déjà rencontré ce problème lors de l’étude de ES6 dans le précédent chapitre. On a vu
que l’utilisation de la nouvelle syntaxe avec les caractères => pour définir une fonction pouvait
impacter la valeur de l’objet this. Utilisons cette syntaxe pour définir la fonction de callback
utilisée dans la méthode map().
67756-React.js-INT.book Page 69 Friday, March 1, 2019 7:15 PM
Hello React
69
CHAPITRE 2
Figure 2–14
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
React.js
70
La seule différence avec le précédent programme est l’utilisation de la syntaxe avec les
caractères => en remplacement du mot-clé function lors de la définition de la fonction de
callback dans la méthode map().
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Figure 2–15
Les éléments de liste sont maintenant de couleur rouge, comme indiqué dans les attributs lors de
la création de la liste. La variable this est maintenant la même dans la fonction de callback et à
l’extérieur de celle-ci, grâce à l’utilisation de la syntaxe ES6 pour les définitions de fonctions.
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
3
React et JSX
Dans le précédent chapitre, nous avons vu comment créer des éléments React et comment les
afficher dans la page HTML. Vous avez pu constater que pour créer les éléments React, tout
repose sur la méthode React.createElement(), puis sur la méthode ReactDOM.render()
lorsqu’il s’agit d’afficher ces éléments dans la page HTML.
Toutefois, la construction d’une arborescence d’éléments React au moyen de
React.createElement() n’est pas chose aisée. De plus, cette méthode ne permet pas de bien
visualiser l’arborescence qui sera effectivement construite (du fait du mélange d’instructions
JavaScript avec du code HTML au milieu).
Les concepteurs de React ont donc cherché un moyen d’alléger l’écriture et leur choix s’est
porté sur l’utilisation de JSX (JavaScript eXtension). JSX est une forme d’écriture des élé-
ments React, plus simple à lire et à écrire que les instructions React.createElement(). Cette
syntaxe est donc abondamment utilisée dans les programmes React.
React.js
72
Cela ressemble à une chaîne de caractères, mais elle n’est pas entourée des guillemets (simples
ou doubles) symbolisant la chaîne de caractères. En fait nous avons ici écrit un élément React,
en JSX.
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Attention
Ne saisissez pas de guillemets lors de l’écriture de code JSX, sinon ce n’est plus du code JSX, mais une
chaîne de caractères !
Toutefois, si l’on écrit ce morceau de programme dans notre page HTML, il ne sera pas cor-
rectement interprété comme on peut le voir dans le message d’erreur suivant.
Figure 3–1
Ce message d’erreur (Unexpected token <) est normal, car on ne peut pas écrire du code
HTML au milieu du code JavaScript. Il aurait fallu ajouter des guillemets autour du code
JSX, mais si on le fait ce n’est plus du code JSX que l’on écrit, c’est une chaîne de caractères.
Pour résoudre le problème et éliminer le message d’erreur, il faut que le code JSX que l’on
écrit soit préalablement traduit en vrai code JavaScript. Ici, il faut le traduire en éléments
React. On utilise pour cela un outil appelé Babel, qui permet d’interpréter le code JSX et de le
transformer en interne en code JavaScript compréhensible par le navigateur. D’autres outils
existent, nous utiliserons celui-ci.
La page HTML utilisant Babel s’écrit de la façon suivante, en intégrant notre code JSX.
67756-React.js-INT.book Page 73 Friday, March 1, 2019 7:15 PM
React et JSX
73
CHAPITRE 3
<html>
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
<head>
<script crossorigin
src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin
src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="app"></div>
</body>
<script type="text/babel">
</script>
</html>
On inclut le fichier JavaScript de Babel au moyen de la balise <script src="..."> (cela cor-
respond à l’interpréteur qui traduira le code JSX en code JavaScript), puis on indique quelle
partie du code JavaScript est à interpréter par Babel. Pour cela, on inclut l’attribut
type="text/babel" dans la balise <script> contenant notre code JavaScript (et JSX).
Le code JavaScript permettant la création des éléments React est écrit en JSX (et sera traduit
en JavaScript pur par Babel), tandis que les éléments React ainsi créés seront insérés dans la
page HTML au moyen de l’instruction ReactDOM.render() (comme on le faisait dans le cha-
pitre précédent).
L’affichage correspond au paragraphe contenant "Hello React", tandis que l’onglet React de
la fenêtre des outils de développement montre l’élément React créé suite à la transformation
du code JSX par Babel (figure 3-2).
Remarquons que l’inclusion de Babel pour interpréter le code JSX ralentit le programme, vu
qu’une étape de traduction est nécessaire avant d’exécuter le code JavaScript. Par conséquent,
l’utilisation de Babel ne peut être viable que dans le cadre de l’écriture du programme (en
mode développement). Cet outil ne peut pas être utilisé dans le cadre d’un déploiement
(mode production). Dans ce dernier cas, on utilisera d’autres outils tels que Webpack pour
créer un package plus compact.
67756-React.js-INT.book Page 74 Friday, March 1, 2019 7:15 PM
React.js
74
Figure 3–2
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Le code généré par Babel s’affiche dans la fenêtre de droite sur la page du site de Babel. Il est
retranscrit ci-dessous.
67756-React.js-INT.book Page 75 Friday, March 1, 2019 7:15 PM
React et JSX
75
CHAPITRE 3
"use strict";
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : { default: obj };
}
var p = _react2.default.createElement(
"p",
null,
"Hello React"
);
_reactDom2.default.render(p, document.body);
<html>
<head>
<script crossorigin
src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin
src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
67756-React.js-INT.book Page 76 Friday, March 1, 2019 7:15 PM
React.js
76
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
<body>
<div id="app"></div>
</body>
<script type="text/babel">
</script>
</html>
Le code JSX est facile à lire et à écrire. Il s’écrit comme du code HTML, mais il est saisi dans
la partie réservée au code JavaScript (dans la balise <script>). Une même instruction peut
s’écrire sur plusieurs lignes et doit obligatoirement commencer par une balise ouvrante et se
terminer par balise fermante (ici, <ul> et </ul>).
67756-React.js-INT.book Page 77 Friday, March 1, 2019 7:15 PM
React et JSX
77
CHAPITRE 3
Figure 3–3
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
<style type="text/css">
.red {
color : red;
}
</style>
La balise <style> doit être insérée dans la partie <head> de la page, comme on l’avait fait
dans le chapitre précédent.
67756-React.js-INT.book Page 78 Friday, March 1, 2019 7:15 PM
React.js
78
Le programme qui insère le code JSX utilisant les attributs id et className est le suivant.
Les attributs id et className sont insérés dans le code JSX sous forme de chaîne de caractères.
Figure 3–4
La liste définie par <ul> possède bien l’id "list1", tandis que la classe CSS red est bien
définie sur la liste (les éléments de liste sont de couleur rouge).
React et JSX
79
CHAPITRE 3
précédés par un point. La propriété color sera également définie dans le style à la valeur
"red" (on suppose que l’on enlève l’attribut className utilisé précédemment de façon à ce
que la couleur des éléments de liste ne soit pas définie à deux endroits).
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
React.js
80
tructions JavaScript avec des accolades. Chaque instruction entourée d’accolades est évaluée
par le navigateur, et son résultat est inséré en lieu et place de l’instruction JavaScript évaluée.
Ceci permet de créer du code JSX qui s’adapte aux conditions définies dans le programme.
Supposons que le style précédent soit en réalité calculé par le programme, au moyen de diffé-
rentes instructions dans celui-ci.
React et JSX
81
CHAPITRE 3
Les instructions JavaScript dans un bloc de code JSX doivent être entourées par des acco-
lades, en particulier l’instruction elems.map(). De même, dans chaque instruction JSX, toute
expression JavaScript doit être encadrée par des accolades, d’où leur présence dans
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
{styleListe} et {index}.
L’attribut key est similaire à celui utilisé dans le précédent chapitre et permet d’éviter un aver-
tissement lors de l’exécution du code (message d’erreur « Each child in an array or iterator
should have a unique "key" prop. »).
En utilisant la notation => (disponible dans ES6) pour définir la fonction de callback, on peut
écrire plus simplement le code suivant.
Ce qui peut aussi s’écrire de façon encore plus raccourcie (les accolades et l’instruction return
dans la fonction de callback ne sont pas nécessaires si une seule instruction est présente dans
les accolades).
Utiliser la notation ES6 sans accolades ni instruction return dans la fonction de callback
React.js
82
éléments React (écrits en JSX). On va donc ici apprendre à créer l’élément <ListeElements> qui
représentera la liste <ul> contenant les éléments <li>.
ReactDOM.render(<ListeElements/>, document.getElementById("app"));
React et JSX
83
CHAPITRE 3
Figure 3–6
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Retourner uniquement les éléments <li> dans la fonction (sans l’élément <ul>)
ReactDOM.render(<ul><ListeElements/></ul>, document.getElementById("app"));
La fonction ne retourne plus l’élément <ul>, donc les accolades qui servaient à indiquer le
code JavaScript à l’intérieur du code JSX ne sont ici plus nécessaires (et si vous les laissez, elles
provoquent une erreur).
En revanche, la méthode ReactDOM.render() doit retourner le code JSX complet, incluant
l’élément <ul>.
Même si l’affichage de la liste est identique au précédent, on voit ici que les éléments React
et <ListeElements> ont été inversés dans l’arborescence.
<ul>
67756-React.js-INT.book Page 84 Friday, March 1, 2019 7:15 PM
React.js
84
Figure 3–7
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
React et JSX
85
CHAPITRE 3
Le style est indiqué comme d’habitude sous forme d’objet JSON (ici, { color:"red" }), et
comme c’est une instruction JavaScript, il faut l’entourer des accolades, d’où les doubles acco-
lades que l’on peut voir ici dans l’élément JSX.
Ce style est récupéré dans la fonction au moyen du paramètre props, et il est accédé à l’aide
de props.style dans l’élément JSX définissant chaque élément <li>.
Modifions ce programme afin de transmettre non pas l’attribut style dans l’élément JSX,
mais directement la propriété color, qui devra alors être positionnée dans le style de chaque
élément de liste <li> (figure 3-8).
67756-React.js-INT.book Page 86 Friday, March 1, 2019 7:15 PM
React.js
86
Figure 3–8
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
L’attribut color est positionné dans l’élément JSX, puis est récupéré dans la fonction au
moyen de props.color. Cette valeur doit être positionnée dans un objet définissant le style
(ici, {color:props.color}), et comme ceci est une instruction JavaScript dans du code JSX,
il faut l’entourer à nouveau des accolades afin qu’elle soit évaluée. D’où les doubles accolades
utilisées pour définir le style dans la fonction.
67756-React.js-INT.book Page 87 Friday, March 1, 2019 7:15 PM
React et JSX
87
CHAPITRE 3
Figure 3–9
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
On voit dans l’onglet React que l’attribut color est bien transmis à l’élément JSX
<ListeElements>, puis que la propriété CSS color est ensuite affectée au style de chaque élé-
ment de liste <li>.
Utilisons maintenant la déstructuration des objets permise par ES6 pour ne plus indiquer
l’objet props en paramètre, mais plutôt ses propriétés elems et color ici utilisées.
React.js
88
Le composant <Element> est lui aussi créé avec une fonction dans laquelle les attributs index,
color et elem sont transmis en paramètres dans l’objet props (ici, utilisé sous forme déstruc-
turée). L’attribut key est utilisé pour éviter l’erreur classique de React indiquant que cet
attribut est obligatoire. Toutefois, il ne sert qu’à mettre une clé différente sur les éléments
issus d’une fonction d’itération, donc il est utilisé dans l’écriture de l’élément <Element> (écrit
dans une boucle d’itération), mais pas dans les paramètres de la fonction Element().
67756-React.js-INT.book Page 89 Friday, March 1, 2019 7:15 PM
React et JSX
89
CHAPITRE 3
Figure 3–10
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Dans l’onglet React, on voit que le composant <ListeElements> contient les composants
<Element> comme demandé.
React.js
90
render() {
return <li style={{color:this.props.color}}>{this.props.elem}</li>
}
}
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
L’instruction ReactDOM.render() est la même que celle utilisée dans la section précédente.
On transmet dans la classe ListeElements les attributs elems et color, utilisés dans la classe
via l’objet this.props qui les contient.
Remarquez que la fonction de callback utilisée dans la méthode map() est définie via la nota-
tion ES6 (avec => au lieu de function), ceci afin de ne pas perdre la valeur de l’objet this
dans la fonction de callback (this.props peut donc être accessible dans la fonction de call-
back afin que sa propriété color soit utilisée).
Dans la classe Element, remarquez l’utilisation des doubles accolades pour définir le style : la
première paire d’accolades est utilisée pour indiquer une instruction JavaScript, la seconde est
utilisée pour écrire l’objet sous forme JSON.
On voit sur l’exemple précédent l’utilité de la notation des fonctions en ES6 (avec les
caractères =>) qui évite de perdre la valeur de this dans une fonction de callback. Toutefois,
on peut écrire le programme de façon légèrement différente et ne pas perdre la valeur de this
tout en utilisant le mot-clé function pour la fonction de callback.
Pour cela, il suffit de mémoriser la valeur de l’attribut color qui est utilisé via this.props.color,
en dehors de la fonction de callback, avant que la valeur de this ne soit perdue (figure 3-11).
67756-React.js-INT.book Page 91 Friday, March 1, 2019 7:15 PM
React et JSX
91
CHAPITRE 3
Figure 3–11
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Mémoriser la valeur des attributs avant leur utilisation dans la fonction de callback
React.js
92
})
}
</ul>
}
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
On récupère (ici, grâce à la déstructuration des objets de ES6) les valeurs des attributs elems
et color (initialement stockés par React dans this.props), puis on utilise ces valeurs elems et
color dans la suite de la méthode render() de la classe ListeElements. Même si la valeur de
this a été modifiée dans la fonction de callback, cela ne cause aucun problème vu qu’il n’est
plus utilisé maintenant...
React et JSX
93
CHAPITRE 3
unique), les autres éléments étant ses enfants. En général on utilise un élément <div> englobant
l’ensemble, mais React propose aussi d’utiliser un composant <React.Fragment> jouant ce rôle.
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Remarque
Cette règle est valable également si on utilise la méthode React.createElement(), avec laquelle on
doit retourner également un seul élément React parent.
function ListeElements(props) {
return <React.Fragment>
<div>Element1</div>
<div>Element2</div>
<div>Element3</div>
</React.Fragment>
}
On retourne bien un seul élément parent qui est l’élément <React.Fragment> défini dans
React.
L’élément <React.Fragment> permet de retourner un seul parent, en évitant l’ajout d’un
nouvel élément parent non nécessaire.
Remarquez que React ne visualise pas l’élément <React.Fragment> dans l’arborescence des
éléments React.
67756-React.js-INT.book Page 94 Friday, March 1, 2019 7:15 PM
React.js
94
Figure 3–12
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
function ListeElements(props) {
return <ul>
<li>Element1</li>
<li>Element2</li>
<li>Element3</li>
<li>Element4</li>
<li>Element5</li>
</ul>
}
React et JSX
95
CHAPITRE 3
La liste des éléments <li> est décalée vers la droite pour montrer visuellement l’imbrication
dans l’élément <ul>.
En utilisant des parenthèses en début et en fin du code JSX retourné, l’écriture du code JSX
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
function ListeElements(props) {
return (
<ul>
<li>Element1</li>
<li>Element2</li>
<li>Element3</li>
<li>Element4</li>
<li>Element5</li>
</ul>
)
}
Sans la parenthèse qui suit l’instruction return, une erreur de syntaxe se produirait.
function ListeElements(props) {
return (
<ul>
<li>Element1</li>
{/* <li>Element2</li>
<li>Element3</li>*/}
<li>Element4</li>
<li>Element5</li>
</ul>
)
}
React.js
96
Dans les deux exemples de programmes, les éléments mis en commentaires n’apparaissent pas
à l’affichage (figure 3-13).
Figure 3–13
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
function ListeElements(props) {
return (
<ul>
67756-React.js-INT.book Page 97 Friday, March 1, 2019 7:15 PM
React et JSX
97
CHAPITRE 3
<li>Element5</li>
</ul>
)
}
Si aucun élément ne doit être affiché, il faut indiquer null, sinon on indique l’élément de liste
en JSX. Cette ligne peut également être écrite de façon encore plus concise :
La figure 3-14 montre le cas où l’on souhaite cacher le premier élément de liste
(hideFirstItem positionné à true) :
Figure 3–14
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
4
Objet state
L’objet state est un objet associé à un composant React, qui peut être créé (pour chaque
composant) dans le constructeur d’une classe dérivant de React.Component. Cet objet s’utilise
uniquement dans les composants créés avec une classe, et ne s’utilise donc pas pour les com-
posants créés avec des fonctions.
L’objet state permet d’indiquer l’état du composant (avec des propriétés que l’on définit en
interne dans la classe), sachant que si cet état est modifié (via la modification d’une ou plusieurs
de ses propriétés), le composant est réaffiché (sa méthode render() est alors de nouveau
appelée). C’est la seule façon de provoquer l’affichage du composant (en dehors de sa création).
Ainsi, pour modifier l’affichage d’un composant React, il faudra modifier l’objet state. Et
pour modifier l’objet state (en réalité this.state, this représentant l’objet associé au com-
posant), il faudra que le composant associé soit créé via une classe, et non pas une fonction.
Remarquons que si un composant se réaffiche, tous les composants internes à celui-ci se réaf-
fichent également, qu’ils aient été créés sous forme de classe ou de fonction.
React.js
100
super(props);
}
render() {
return <div>01:00</div>
}
}
ReactDOM.render(<Alarme/>, document.getElementById("app"));
Figure 4–1
Le composant Alarme s’affiche à sa valeur initiale (01:00), mais on voit tout de suite le pro-
blème. Comment faire pour décrémenter l’affichage toutes les secondes ? En fait, il faudrait
pouvoir modifier l’affichage lorsqu’on le souhaite... C’est le rôle de l’objet state.
Comme le temps restant varie (à chaque seconde), il ne doit pas être figé comme ici à 01:00,
mais il doit être placé dans une variable qui sera modifiée chaque seconde. Nous positionnons
le temps restant dans l’objet state, et nous décrémentons ce temps restant à chaque seconde
grâce à un timer positionné dans le constructeur de la classe, en utilisant la fonction
setInterval() de JavaScript.
67756-React.js-INT.book Page 101 Friday, March 1, 2019 7:15 PM
Objet state
101
CHAPITRE 4
super(props);
this.state = { min : 1, sec : 0 }; // Créer l’objet state dans le composant
setInterval(() => {
this.state = this.decrTime(this.state); // Décrémenter de 1 seconde
console.log(this.state); // Afficher l’objet state dans la console
}, 1000); // 1000 millisecondes = 1 seconde
}
decrTime({min, sec}) {
// Décrémenter sec de 1 seconde, en diminuant si besoin min
// 01:10 => 01:09
// 01:00 => 00:59
sec = sec - 1;
if (sec < 0) {
min = min - 1;
if (min < 0) {
min = 0;
sec = 0;
}
else {
sec = 59;
}
}
return { min, sec };
}
formatTime({min, sec}) {
// Formater l’heure sous la forme mm:ss
if (min < 10) min = "0" + min; // 9 => "09"
if (sec < 10) sec = "0" + sec; // 9 => "09"
return `${min}:${sec}`; // de la forme "10:08"
}
render() {
return <div>{this.formatTime(this.state)}</div>
}
}
ReactDOM.render(<Alarme/>, document.getElementById("app"));
L’objet this.state est créé dans le constructeur de la classe et il est initialisé avec l’objet
{ min:1, sec:0 } correspondant à une alarme de 1 minute.
Le timer est positionné juste après par setInterval() et il décrémente (chaque seconde) les
valeurs { min, sec } de l’objet state de 1 seconde.
La fonction de callback utilisée dans setInterval() est écrite dans la notation ES6, afin de
conserver la valeur de this (qui sinon devient égale à l’objet window dans la fonction de callback).
Les méthodes decrTime() et formatTime() sont des méthodes utilitaires permettant respec-
tivement de diminuer le temps de 1 seconde, et d’afficher le temps sous la forme mm:ss.
67756-React.js-INT.book Page 102 Friday, March 1, 2019 7:15 PM
React.js
102
Figure 4–2
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
On peut voir que le temps diminue dans la console, mais pas à l’affichage dans la page
HTML ! En fait, bien que l’état soit mis à jour, il manque encore une instruction qui permet-
trait de rafraîchir le composant.
En effet, après que l’objet state ait été mis à jour, il faut indiquer à React que cet objet a été
modifié (ce qui provoquera un nouvel appel à la méthode render()). Pour cela, on utilise la
méthode this.setState(newState), dans laquelle newState est un objet indiquant les
valeurs des propriétés modifiées dans l’objet state. Ici, il faudrait indiquer un objet { min,
sec } avec les nouvelles valeurs.
Si seule la propriété sec est indiquée dans l’objet newState lors de l’instruction
this.setState(newState), l’affichage des minutes ne sera jamais modifié et seules les
secondes seront décrémentées en revenant à 59 après avoir atteint 0. Cela montre que pour
modifier l’affichage, il faut indiquer dans l’objet newState toutes les propriétés qui ont été
changées dans celui-ci.
L’objet state ne doit jamais être modifié directement, sauf lors de sa création. Il ne peut être
modifié ensuite qu’avec this.setState(newState), ce qui remplace les propriétés de
this.state par celles indiquées dans newState (les propriétés non indiquées ou non modi-
fiées dans newState sont laissées telles quelles dans this.state).
67756-React.js-INT.book Page 103 Friday, March 1, 2019 7:15 PM
Objet state
103
CHAPITRE 4
ReactDOM.render(<Alarme/>, document.getElementById("app"));
L’instruction this.setState() prend en arguments les valeurs min et sec de l’objet newState.
On aurait pu aussi écrire l’instruction sous la forme this.setState(newState), car newState
contient les propriétés min et sec.
Après quelques secondes, l’affichage change (figure 4-3).
L’appel de la méthode this.setState() provoque bien la mise à jour de l’affichage (donc du
composant).
67756-React.js-INT.book Page 104 Friday, March 1, 2019 7:15 PM
React.js
104
Figure 4–3
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Utilisation du composant Alarme en réglant les minutes et les secondes dans les attributs
Les valeurs min et sec sont maintenant indiquées dans les attributs du composant Alarme, qui
doit les utiliser pour démarrer son comptage.
Remarquez l’utilisation des accolades autour des attributs numériques. En effet, la valeur
d’un attribut en JSX doit être spécifiée soit sous forme d’expressions JavaScript (donc
entourée d’accolades comme ici), soit sous forme de chaîne de caractères (donc entourée des
guillemets simples ou doubles).
Écrivons le nouveau composant Alarme qui utilise ces attributs. Ces derniers seront transmis dans
l’objet props utilisé dans le constructeur du composant (comme vu dans le chapitre précédent).
67756-React.js-INT.book Page 105 Friday, March 1, 2019 7:15 PM
Objet state
105
CHAPITRE 4
super(props);
this.state = { min : props.min, sec : props.sec };
setInterval(() => {
var newState = this.decrTime(this.state);
console.log(newState);
this.setState({min : newState.min, sec : newState.sec });
}, 1000);
}
decrTime({min, sec}) {
// Même chose que pour le programme précédent
// ...
}
formatTime({min, sec}) {
// Même chose que pour le programme précédent
// ...
}
render() {
return <div>{this.formatTime(this.state)}</div>
}
}
L’objet state est mis à jour depuis l’objet props, contenant les attributs min et sec utilisés
dans le composant.
React.js
106
}
decrTime({min, sec}) {
// Même chose que pour le programme précédent
// ...
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
}
formatTime({min, sec}) {
// Même chose que pour le programme précédent
// ...
}
render() {
if (this.state.min == 0 && this.state.sec == 0) {
clearInterval(this.timer);
return <div>Fin de l’alarme</div>
}
return <div>{this.formatTime(this.state)}</div>
}
}
Lorsque le timer est à 0 (min et sec sont à 0 dans this.state), il est arrêté au moyen de
clearInterval(this.timer), this.timer étant mémorisé lors de la création du timer par
setInterval().
Dans ce cas (timer à 0), on retourne un code JSX différent de celui où le timer est encore en cours.
Vérifions sur la figure 4-4 que cela fonctionne correctement (le timer est ici de 5 secondes).
Figure 4–4
67756-React.js-INT.book Page 107 Friday, March 1, 2019 7:15 PM
Objet state
107
CHAPITRE 4
Lorsqu’un composant React est créé (ici, au moyen d’une classe dérivant de
React.Component), certaines méthodes internes à la classe sont appelées automatiquement
par React. Ces méthodes peuvent être surchargées dans la classe du composant afin d’effec-
tuer des traitements spécifiques lors du cycle de vie de ce composant.
Le cycle de vie d’un composant React comporte trois étapes fondamentales :
• la création du composant ;
• la mise à jour du composant ;
• la destruction du composant.
Étudions à présent les méthodes proposées par React pour chacune des étapes du cycle de vie
d’un composant.
Ces méthodes ne sont disponibles que si le composant est créé sous forme de classe, et non
pas sous forme de fonction JavaScript.
React.js
108
Note
Pour savoir si les propriétés ont été modifiées, il suffit de comparer nextProps (nouvelles propriétés) et
this.props (anciennes propriétés).
Objet state
109
CHAPITRE 4
React.js
110
Figure 4–5
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Note
Les méthodes de mise à jour ou de destruction ne sont bien sûr pas appelées ici.
À la suite des méthodes de création du composant (qui ne sont appelées qu’une seule fois,
pour le premier affichage), on peut voir les méthodes de mise à jour (elles utilisent les nou-
velles props).
Plutôt que de mettre à jour le même composant dans le même élément DOM, créons un second
élément DOM <div id="app2"> que l’on utilise pour effectuer le second ReactDOM.render()
(figure 4-7).
67756-React.js-INT.book Page 111 Friday, March 1, 2019 7:15 PM
Objet state
111
CHAPITRE 4
Figure 4–6
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
<body>
<div id="app"></div>
<div id="app2"></div>
</body>
<script type="text/babel">
// …
ReactDOM.render(<HelloReact a="1"/>, document.getElementById("app"));
ReactDOM.render(<HelloReact a="2"/>, document.getElementById("app2"));
</script>
Deux composants <HelloReact> sont affichés dans la page, chacun étant créé indépendam-
ment de l’autre (car ils sont associés à des éléments DOM différents) (figure 4-7).
Enfin, si l’on détruit le composant après l’avoir créé :
67756-React.js-INT.book Page 112 Friday, March 1, 2019 7:15 PM
React.js
112
Figure 4–7
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Objet state
113
CHAPITRE 4
Figure 4–8
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
setTimeout(function() {
// Alarme sur 2 minutes à la fin de la première alarme
ReactDOM.render(<Alarme min={2} sec={0}/>, document.getElementById("app"));
}, 5000); // 5 secondes
La première alarme est programmée sur une durée de 5 secondes et dès qu’elle arrive à son
terme, elle est repositionnée pour une durée de 2 minutes.
67756-React.js-INT.book Page 114 Friday, March 1, 2019 7:15 PM
React.js
114
Figure 4–9
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Une fois les 5 secondes de la première alarme écoulées, la seconde alarme est positionnée (on
le voit dans l’objet props qui est mis à jour). Cependant, elle ne se met pas en route pour
autant (du moins l’affichage ne le montre pas car il reste bloqué sur Fin de l’alarme).
Le problème que l’on observe vient du cycle de vie que l’on a précédemment étudié. En effet,
l’instruction this.setState() qui permet de déclencher le render() interne au composant
n’est exécutée que dans le constructeur de la classe. Or ce constructeur n’est plus appelé lors
de l’affichage du second composant <Alarme>, car on utilise le même élément DOM pour
afficher les deux composants (dans les deux cas on utilise l’élément DOM dont l’id est
"app"). Pour que cela fonctionne, il faudrait donc mettre le second composant <Alarme> dans
un nouvel élément DOM, par exemple en écrivant le code suivant.
Insertion du second composant <Alarme> dans un élément DOM dont l’id est "app2"
setTimeout(function() {
ReactDOM.render(<Alarme min={2} sec={0}/>, document.getElementById("app2"));
}, 5000);
Le second composant <Alarme> est positionné dans un élément <div id="app2">, tandis que
le premier composant <Alarme> reste quant à lui positionné dans un élément <div id="app">.
67756-React.js-INT.book Page 115 Friday, March 1, 2019 7:15 PM
Objet state
115
CHAPITRE 4
Figure 4–10
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Cela fonctionne, mais on a maintenant deux composants affichés, ce qui n’est pas vraiment
encore ce que l’on souhaite...
Pour ne pas avoir deux composants <Alarme> affichés et conserver uniquement le premier, il
faut utiliser la méthode componentWillReceiveProps(). En effet, contrairement aux
méthodes de construction du composant qui ne sont appelées qu’une seule fois (ce qui pose
problème ici), cette méthode est appelée chaque fois que le composant reçoit des propriétés
(modifiées ou non par rapport aux anciennes). Il suffit donc dans cette méthode
componentWillReceiveProps() d’effectuer l’appel à this.setState() pour demander un
nouveau render() en utilisant maintenant les nouvelles propriétés transmises.
React.js
116
decrTime({min, sec}) {
// Décrémenter sec de 1 seconde, en diminuant si besoin min
// 01:10 => 01:09
// 01:00 => 00:59
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
sec = sec - 1;
if (sec < 0) {
min = min - 1;
if (min < 0) {
min = 0;
sec = 0;
}
else {
sec = 59;
}
}
return { min, sec };
}
formatTime({min, sec}) {
// Formater l’heure sous la forme mm:ss
if (min < 10) min = "0" + min; // 9 => "09"
if (sec < 10) sec = "0" + sec; // 9 => "09"
return `${min}:${sec}`; // de la forme "10:08"
}
render() {
if (this.state.min == 0 && this.state.sec == 0) {
clearInterval(this.timer);
return <div>Fin de l’alarme</div>
}
return <div>{this.formatTime(this.state)}</div>
}
componentWillReceiveProps(nextProps) {
this.setState({min : nextProps.min, sec : nextProps.sec }); // => render()
this.timer = setInterval(() => {
var newState = this.decrTime(this.state);
console.log(newState);
this.setState({min : newState.min, sec : newState.sec });
}, 1000);
}
}
setTimeout(function() {
ReactDOM.render(<Alarme min={2} sec={0}/>, document.getElementById("app"));
}, 5000);
Lors de la réception des nouvelles propriétés, on les positionne dans l’objet state et on
réarme le timer qui avait été arrêté précédemment.
La seconde alarme remplace la première dès que celle-ci est arrivée à échéance.
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Figure 4–11
67756-React.js-INT.book Page 117 Friday, March 1, 2019 7:15 PM
CHAPITRE 4
Objet state
117
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
67756-React.js-INT.book Page 118 Friday, March 1, 2019 7:15 PM
67756-React.js-INT.book Page 119 Friday, March 1, 2019 7:15 PM
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
5
Interactions dans
les composants React
Dans les précédents chapitres, nous avons créé des composants React. Nous allons à présent
voir comment interagir avec eux (par exemple, comment gérer le clic sur un élément de liste
ou sur un bouton ?).
React.js
120
L’attribut onclick utilisé en HTML devient donc onClick dans les propriétés (attributs) de
l’élément React.
ReactDOM.render(<ButtonMessage/>, document.getElementById("app"));
L’instruction à exécuter lors du clic est indiquée entre des accolades car c’est une instruction
JavaScript. Une seule instruction peut figurer dans l’expression et elle ne doit pas se terminer
par un point-virgule (contrairement à l’attribut s’il était positionné en HTML) car sinon, une
erreur se produit.
Affichons cette page dans le navigateur, sans cliquer sur le bouton pour l’instant (figure 5-1).
Figure 5–1
On voit que le bouton s’affiche correctement, mais que le clic sur le bouton ne produit aucun
effet.
67756-React.js-INT.book Page 121 Friday, March 1, 2019 7:15 PM
De plus, un clic semble avoir été effectué (affichage du message dans la console) alors que l’on
a simplement affiché le composant, sans avoir cliqué nulle part. Bref, rien ne fonctionne !
Ce simple programme permet de comprendre certaines choses importantes dans le fonction-
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
nement de React. En effet, lorsque l’on écrit une expression entre des accolades (comme
{ console.log(...) } ici), cette expression est directement exécutée lors de l’affichage du
composant, d’où l’affichage du message directement dans la console.
Pour ne pas provoquer son exécution, l’instruction doit être non pas un appel de fonction
comme ici (on appelle la fonction console.log() avec un argument texte), mais une réfé-
rence de fonction (c’est-à-dire le nom de la fonction sans les parenthèses qui suivent, les-
quelles provoquent l’appel de cette fonction). Ainsi, il serait plus judicieux d’écrire
{ console.log } qui est la référence de la fonction demandée, sans les parenthèses.
Gérer le clic sur le bouton en passant par une fonction intermédiaire (callback)
ReactDOM.render(<ButtonMessage/>, document.getElementById("app"));
React.js
122
Figure 5–2
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
ReactDOM.render(<ButtonMessage/>, document.getElementById("app"));
La fonction, ici anonyme (sans nom), est définie directement dans la valeur de l’attribut. On
utilise une fonction anonyme car son nom n’étant utilisé nulle part, il n’a pas besoin d’être
indiqué.
Sur cet exemple, on voit bien que la valeur de l’attribut onClick est une fonction de callback
qui sera appelée lors du déclenchement de l’événement.
67756-React.js-INT.book Page 123 Friday, March 1, 2019 7:15 PM
ReactDOM.render(<ButtonMessage/>, document.getElementById("app"));
Le bouton est défini en JSX dans la méthode render() de la classe. L’attribut onClick est
également utilisé, comme lorsque l’on avait défini le composant sous forme de fonction.
Toutefois, les remarques que l’on avait mentionnées dans la section précédente sont toujours
valables. L’instruction définie dans l’attribut onClick est exécutée lors de l’affichage du com-
posant, et le clic sur le bouton n’est donc pas pris en compte.
Il faut donc également passer par une fonction intermédiaire, et indiquer sa référence dans
l’attribut onClick. On appelle cette fonction intermédiaire traiterClick() comme précé-
demment.
Gérer le clic sur le bouton en passant par une fonction intermédiaire (callback)
function traiterClick() {
console.log("clic sur le bouton");
}
ReactDOM.render(<ButtonMessage/>, document.getElementById("app"));
67756-React.js-INT.book Page 124 Friday, March 1, 2019 7:15 PM
React.js
124
La fonction de traitement du clic est ici définie à l’extérieur de la classe, mais il serait préfé-
rable de la définir à l’intérieur de celle-ci.
Figure 5–3
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
ReactDOM.render(<ButtonMessage/>, document.getElementById("app"));
67756-React.js-INT.book Page 125 Friday, March 1, 2019 7:15 PM
L’accès à la méthode traiterClick() interne à la classe se fait via l’objet this, d’où l’utilisa-
tion de l’instruction this.traiterClick dans l’attribut onClick.
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
ReactDOM.render(<ButtonMessage/>, document.getElementById("app"));
Par rapport au programme précédent, nous avons juste remplacé le texte du message à affi-
cher par le contenu de l’objet this.props.
Après avoir cliqué sur le bouton, le résultat n’est vraiment pas celui attendu (figure 5-4).
Le message d’erreur indique que l’on essaye d’accéder à la propriété props d’une variable qui
a la valeur undefined. Cela signifie que l’objet this auquel on essaye d’accéder dans la fonc-
tion de traitement du clic traiterClick() vaut undefined.
Pourtant, la méthode traiterClick() est bien une méthode interne à la classe du composant,
donc this devrait être définie et ne pas valoir undefined. Cela serait le cas si cette méthode
n’était pas une fonction de callback (appelée suite à un événement), ce qui lui fait perdre la
valeur de this.
Il faut donc trouver une solution qui permettrait de conserver la valeur de this dans la
méthode traiterClick(), qui doit correspondre à la valeur de l’élément JSX
<ButtonMessage> instancié. Pour cela, différentes solutions sont possibles, examinées ci-après.
67756-React.js-INT.book Page 126 Friday, March 1, 2019 7:15 PM
React.js
126
Figure 5–4
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
traiterClick.bind(this);
Lorsque la fonction traiterClick() définie plus haut se déclenchera, la valeur this qui sera
utilisée par celle-ci sera celle définie en arguments de la méthode bind(). Si this correspond
à un élément JSX <ButtonMessage>, ce sera parfait !
En utilisant ce concept dans la classe ButtonMessage, on écrit le code qui suit.
67756-React.js-INT.book Page 127 Friday, March 1, 2019 7:15 PM
super(props);
}
traiterClick() {
console.log(this.props);
}
render() {
return (
<button onClick={this.traiterClick.bind(this)}>Cliquez ici</button>
)
}
}
ReactDOM.render(<ButtonMessage/>, document.getElementById("app"));
Figure 5–5
67756-React.js-INT.book Page 128 Friday, March 1, 2019 7:15 PM
React.js
128
Dès qu’on clique sur le bouton, le contenu de l’objet props associé à l’élément React
<ButtonMessage> s’affiche (ici, un objet vide car aucune props n’est transmise par cet élément).
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
L’instruction bind(this) a été déportée dans le constructeur. Elle sera exécutée pour chaque
création d’élément <ButtonMessage>.
Un attribut msg="Hello" a été ajouté dans <ButtonMessage> afin de l’afficher dans
this.props.
67756-React.js-INT.book Page 129 Friday, March 1, 2019 7:15 PM
Figure 5–6
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Utiliser la définition des fonctions avec les caractères => lors de l’appel
React.js
130
La méthode traiterClick() n’existe plus car son contenu est directement inscrit dans la
valeur de l’attribut onClick (en utilisant la notation avec les caractères =>).
Figure 5–7
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
La valeur this n’est plus perdue grâce à la nouvelle définition des fonctions avec les
caractères =>.
Utiliser la définition des fonctions avec les caractères => lors de l’appel
render() {
return (
<button onClick={this.traiterClick}>Cliquez ici</button>
)
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
}
}
L’utilisation de la définition des méthodes d’une classe avec les caractères => permet de
conserver la valeur de this dans la fonction de callback.
React.js
132
intègre bind(this) dans la valeur de l’attribut et la deuxième qui utilise bind(this) dans le
constructeur, sont celles qui sont les plus utilisées.
Les autres solutions, bien que fonctionnelles, sont cependant moins utilisées. Pour notre part,
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
nous préférons la première solution car elle est la moins verbeuse et elle évite de dupliquer le
nom de la méthode à deux endroits (lors de l’appel et dans le constructeur).
67756-React.js-INT.book Page 133 Friday, March 1, 2019 7:15 PM
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
6
Cas pratique : gérer
les éléments d’une liste
Dans ce chapitre, nous allons voir comment utiliser React pour modifier une liste d’éléments.
Cela va consister à rendre possible les actions suivantes :
• Insertion d’un élément dans la liste : chaque élément inséré est libellé selon sa position
dans la liste ("Element1", puis "Element2", etc.). La liste est vide au départ.
• Suppression d’un élément dans la liste : pour permettre la suppression d’un élément, un
bouton Supprimer est ajouté à la suite du texte de l’élément. Le clic sur ce bouton sup-
prime l’élément correspondant.
• Modification d’un élément dans la liste : suite au double-clic sur le texte d’un élément, un
champ de saisie est affiché, contenant le texte de l’élément. Le texte affiché dans le champ
de saisie est modifiable, et doit être validé en appuyant sur la touche Entrée. Le champ de
saisie est alors remplacé par le texte saisi dans le champ.
Examinons maintenant ces différentes actions.
React.js
134
Remarquons que l’on ne peut pas utiliser l’index de l’élément dans la liste comme clé unique,
car en fonction des insertions et des suppressions, cet index peut varier (et sa mise à jour serait
plus complexe que de définir une clé unique comme ici).
Commençons par voir comment insérer un élément dans la liste.
<html>
<head>
<script crossorigin
src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin
src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="app"></div>
</body>
<script type="text/babel">
this.ukey = props.ukey;
}
render() {
return (
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
<li>{this.props.txt}</li>
)
}
}
React.js
136
</script>
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
</html>
Une fois que l’on sait quels sont les composants à écrire, les propriétés à utiliser pour chaque
composant (via leur objet props), et le state qui sera utilisé (et dans quel composant le
mettre), l’écriture des composants est plus aisée.
Remarquez que this.state.elems est un tableau des éléments insérés, chaque élément étant
repéré par son texte (propriété txt) et sa clé unique (propriété ukey). La clé unique dans
chaque élément servira à identifier l’élément dans le state.
Le composant <Element> inséré dans le composant <ListeElements> possède les deux pro-
priétés key et ukey ayant la même valeur : key est utilisé en interne par React (sinon une erreur
se produit comme expliqué dans les chapitres précédents), tandis que ukey est la clé unique
utilisée par notre programme. Celui-ci ne peut pas utiliser key de façon directe (en dehors de
son initialisation) sinon React produit une erreur, d’où l’utilisation de la propriété ukey.
Remarquez l’utilisation de bind(this) sur la méthode insertElem(), afin que cette dernière
puisse accéder à this.state comme vu dans le chapitre précédent.
Figure 6–1
Chaque clic sur le bouton Insérer ajoute un élément à la liste (ici, cinq éléments insérés).
67756-React.js-INT.book Page 137 Friday, March 1, 2019 7:15 PM
çons par montrer sur quel élément est positionnée la souris, en mettant cet élément en ita-
lique et en couleur rouge.
Il suffit de modifier le composant Element, qui permet d’afficher chacun des éléments de la
liste.
Comme on doit gérer les événements liés à la souris, on utilise les propriétés onMouseOver et
onMouseOut permettant de savoir si la souris entre sur un élément (onMouseOver) ou en sort
(onMouseOut). Le style de l’élément devant être modifié (couleur et mise en italique), ce style
sera mis dans le state associé à chacun des éléments de liste. Le state sera modifié dans les
deux événements liés à la souris.
On aura donc le state global associé au composant App (contenant la liste des éléments de liste
dans this.state.elems, this faisant ici référence au composant App), et un state pour
chaque élément de liste (contenant le style de chaque élément dans this.state.style, this
faisant ici référence au composant Element).
On transmet donc au composant Element une propriété supplémentaire appelée style qui
permettra de connaître le style à afficher pour cet élément de liste.
React.js
138
Le style de l’élément est initialisé dans le state et correspond lors de l’initialisation à un objet
vide {}. Le state est modifié dans les méthodes mouseOver() et mouseOut() appelées lors des
événements onMouseOver et onMouseOut positionnés sur l’élément React <li>.
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
La souris est ici positionnée sur le premier élément inséré, qui est en italique et rouge.
super(props);
this.ukey = props.ukey;
this.state = { style : {}, removed : false };
}
mouseOver() {
var style = { color : "red", fontStyle : "italic" };
this.setState({style : style });
}
mouseOut() {
var style = { color : "", fontStyle : "" };
this.setState({style : style });
}
removeElem() {
this.setState({removed : true });
}
render() {
return (
this.state.removed ? null :
<li style={this.state.style}
onMouseOver={this.mouseOver.bind(this)}
onMouseOut={this.mouseOut.bind(this)} >
<span>{this.props.txt}</span>
<button style={{margin:"10px", fontSize:"10px"}}
onClick={this.removeElem.bind(this)}>
Supprimer
</button>
</li>
)
}
}
Un bouton a été ajouté dans chaque élément de liste, lequel active la méthode removeElem()
définie dans la classe. Cette méthode modifie le state en positionnant sa propriété removed à
la valeur true, ce qui provoque le rafraîchissement du composant.
Dans le cas où this.state.removed vaut true, la méthode render() n’affiche pas d’éléments
React, car elle retourne null (permettant ainsi de ne pas afficher l’élément supprimé).
Après plusieurs insertions et suppressions dans la liste, on obtient par exemple l’affichage
illustré par la figure 6-3.
On voit que les éléments de liste supprimés ne sont effectivement plus affichés dans la page
HTML. Les éléments React sont quant à eux encore présents, comme on peut le voir dans
l’onglet React. C’est pourquoi nous allons maintenant étudier une autre méthode pour sup-
primer un élément dans la liste, qui permettra de rafraîchir la liste des éléments dans le state
global situé dans le composant <App>.
67756-React.js-INT.book Page 140 Friday, March 1, 2019 7:15 PM
React.js
140
Figure 6–3
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
depuis le composant App une propriété, ici nommée app, qui sera transmise aux composants
enfants (ListeElements puis Element), afin que finalement le composant Element l’utilise.
Mettons en œuvre cette solution. Tous les composants sont ici modifiés, donc leur code est
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
indiqué intégralement. Pour l’instant, afin de permettre une bonne compréhension du code à
écrire, on se limite à écrire des traces avec console.log() dans les différentes méthodes
implémentées.
React.js
142
}
</ul>
)
}
}
La modification principale vient de la transmission de la propriété app (qui vaut this dans le
composant App) aux composants ListeElements et Element (dans ces deux derniers compo-
sants, cette propriété est donc accessible via this.props.app).
Lors du clic sur le bouton Supprimer dans la classe Element, on écrit
onClick={this.props.app.removeElem}, ce qui permet d’activer la méthode removeElem()
définie dans la classe App.
Voyons sur la figure 6-4 ce que cela indique en cliquant sur le bouton Insérer puis Supprimer.
67756-React.js-INT.book Page 143 Friday, March 1, 2019 7:15 PM
Figure 6–4
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Lors du clic sur le bouton Supprimer, la méthode removeElem() définie dans le composant
App est bien appelée depuis le composant Element. Mais comment indiquer quel est l’élément
à supprimer (car pour l’instant, on ne fait qu’afficher du texte...) ?
Le but est maintenant d’indiquer l’élément de la liste à supprimer, afin que la méthode
removeElem()le supprime.
Le premier réflexe que l’on pourrait avoir serait d’indiquer l’élément à supprimer (ici, this)
en paramètre de la méthode removeElem(). On serait donc tenté d’écrire quelque chose qui
ressemblerait au code suivant.
React.js
144
mouseOut() {
var style = { color : "", fontStyle : "" };
this.setState({style : style });
}
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
render() {
return (
this.state.removed ? null :
<li style={this.state.style}
onMouseOver={this.mouseOver.bind(this)}
onMouseOut={this.mouseOut.bind(this)} >
<span>{this.props.txt}</span>
<button style={{margin:"10px", fontSize:"10px"}}
onClick={this.props.app.removeElem(this)}
>
Supprimer
</button>
</li>
)
}
}
L’élément à supprimer (this dans ce cas, car on est dans la classe Element) est indiqué en
paramètre lors de l’appel de la méthode removeElem() lors du clic.
Toutefois, ceci ne fonctionnera pas car on ne peut pas indiquer un appel de fonction lors de la
définition d’un événement dans des propriétés comme onClick, car React provoque l’appel
direct de cette fonction (comme on l’a vu en début dans le chapitre précédent lorsqu’on avait
écrit onClick={console.log("...")}).
Ainsi, la seule manière de transmettre à removeElem() l’élément à supprimer est de le lui
indiquer via un bind() lors de la définition du onClick dans la classe Element.
Écrivons donc la définition du bouton (button) du composant Element sous la forme sui-
vante, en utilisant bind() pour indiquer le this à utiliser.
La méthode bind(this) indique ici que removeElem() (définie dans App car on indique
this.props.app devant l’appel) doit utiliser le this indiqué dans le bind(), c’est-à-dire
l’objet de classe Element dans lequel on est actuellement situé.
Cette nouvelle définition avec bind(this) lors de l’écriture de la méthode permet de ne pas
avoir à indiquer un paramètre à la méthode removeElem() (ce paramètre serait bien sûr l’élé-
ment à supprimer) car elle peut utiliser le this qu’on lui a indiqué ici.
Écrivons maintenant la méthode removeElem() en affichant l’objet this qui lui est associé.
67756-React.js-INT.book Page 145 Friday, March 1, 2019 7:15 PM
removeElem() {
console.log(this); // Élément à supprimer
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
L’objet this utilisé dans la méthode removeElem() est celui défini lors de l’écriture de
l’attribut onClick du bouton (button) dans la classe Element, grâce au bind(this) effectué.
Exécutons ce programme en insérant et en supprimant quelques éléments (figure 6-5).
Figure 6–5
Trois éléments ont été insérés, puis deux ont été supprimés comme on peut le voir dans la
console. De plus, ce sont bien des objets Element que l’on récupère avec l’objet this dans la
méthode removeElem().
À ce stade, on pourrait penser que la solution a été trouvée ! Malheureusement, ce n’est pas
(encore) le cas.
En effet, n’oublions pas que le but de tout cela est de permettre l’accès au state du composant
App, depuis la méthode removeElem() définie dans ce même composant (pour avoir accès à
this.state.elems et le mettre à jour). Mais ce n’est maintenant plus possible car this.state
fait référence au state défini dans la classe Element (ce qui est normal car this vaut un objet
de classe Element à cause du bind() effectué précédemment) et il faudrait ici (dans la
67756-React.js-INT.book Page 146 Friday, March 1, 2019 7:15 PM
React.js
146
méthode removeElem() définie dans le composant App) plutôt accéder au state défini dans la
classe App (lequel définit this.state.elems). C’est l'histoire du serpent qui se mord la queue
(this doit valoir l’objet de classe Element, et en même temps l’objet de classe App)...
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Néanmoins, la solution n’est pas si lointaine que cela ! Il suffit que dans la définition de la pro-
priété onClick écrite dans le bouton (button), on ne fasse plus le bind() à cet endroit (le bind()
à cet emplacement conduit à une situation sans solution comme on vient de le voir). Pour cela, on
utilise une méthode intermédiaire (ici appelée handlerRemoveElem(), le préfixe handler signi-
fiant qu’elle est intermédiaire) définie dans la classe Element (classe qui utilise le composant
<button>) qui sera celle qui appellera la méthode removeElem() définie dans la classe App, en lui
indiquant en paramètre l’élément à supprimer (ici, objet this de classe Element).
Nous indiquons la totalité du code des composants afin de bien visualiser les changements
effectués.
render() {
return (
<ul>
{
this.props.elems.map((elem, index) => {
var { ukey, txt } = elem;
return <Element key={ukey} ukey={ukey} txt={txt} app={this.props.app} />
})
}
</ul>
)
}
}
React.js
148
Les objets de classe Element sont affichés dans la console suite aux clics sur les boutons Sup-
primer correspondants. Le fonctionnement est donc correct.
Il reste maintenant à implémenter la gestion du state dans la classe App afin de supprimer
l’élément dans la liste lors du clic sur le bouton Supprimer. La méthode filter() de la classe
Array de JavaScript permet (via une fonction de callback) de retourner un nouveau tableau à
partir d’un tableau initial. Il suffit d’indiquer pour chaque élément du tableau d’origine si on
le conserve (la fonction de callback doit retourner true dans ce cas) ou si on le supprime (ne
rien retourner ou retourner false).
La méthode removeElem(objElem) du composant App s’écrit alors comme ceci.
67756-React.js-INT.book Page 149 Friday, March 1, 2019 7:15 PM
elems = elems.filter(function(elem) {
if (objElem.ukey != elem.ukey) return true; // Conserver l’élément
});
this.setState({ elems : elems });
}
On filtre l’élément à supprimer via la clé unique (propriété ukey). On conserve tous les élé-
ments sauf celui qui a la même clé que celui à supprimer (transmis en paramètres).
Figure 6–7
Après insertion et suppression de quelques éléments de la liste, on peut voir que l’objet
this.state.elems est mis à jour (et l’affichage de la liste en tient compte grâce à React qui
met à jour l’affichage en fonction du state).
Le but de cet exemple était de montrer comment on peut mettre à jour le state d’un compo-
sant parent, ce qui est un cas fréquent lors de l’utilisation de React. On transmet le compo-
sant parent (en fait son instance correspondant à l’objet React) via l’objet props, puis on
implémente dans le composant enfant une méthode handlerXXX() qui effectue l’appel de la
méthode XXX() associée du composant parent.
67756-React.js-INT.book Page 150 Friday, March 1, 2019 7:15 PM
React.js
150
ments insérés sont toujours mis sous la forme Element1, Element2, etc., mais si on double-
clique sur un élément, il se transforme maintenant en un champ de saisie que l’on peut modi-
fier. L’appui sur la touche Entrée permet de valider la saisie et de revenir en mode visualisation.
Pour réaliser cela, procédons par étapes.
1 La première étape va consister à afficher un champ de saisie lors du double-clic sur un élément
de la liste. Le champ de saisie sera initialisé avec la valeur de l’élément sur lequel on a cliqué.
2 Ensuite, on verra comment prendre en compte la saisie dans le champ.
3 Enfin, on terminera en confirmant la saisie lors de l’appui sur la touche Entrée.
mouseOver() {
var style = { color : "red", fontStyle : "italic" };
this.setState({style : style });
}
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
mouseOut() {
var style = { color : "", fontStyle : "" };
this.setState({style : style });
}
handlerRemoveElem() {
this.props.app.removeElem(this); // this : objet de classe Element
}
modifyElem() {
this.setState({ modifyOn : true });
}
render() {
return (
this.state.removed ? null :
<li style={this.state.style}
onMouseOver={this.mouseOver.bind(this)}
onMouseOut={this.mouseOut.bind(this)}
onDoubleClick={this.modifyElem.bind(this)} >
{ this.state.modifyOn ?
<input type="text" value={this.props.txt}/> :
<span>{this.props.txt}</span>
}
<button style={{margin:"10px", fontSize:"10px"}}
onClick={this.handlerRemoveElem.bind(this)}
>
Supprimer
</button>
</li>
)
}
}
Un événement onDoubleClick est pris en compte sur l’élément <li>, qui appellera la
méthode modifyElem() qui effectue la mise à true de la propriété modifyOn du state.
De plus, lors de l’affichage de l’élément de liste (méthode render()), on teste la valeur de
modifyOn afin de savoir si l’on affiche l’élément sous forme de <input> (si
this.state.modifyOn est à true) ou sous forme de <span> (si this.state.modifyOn est à
false).
Après avoir inséré quelques éléments et double-cliqué sur certains, on obtient l’affichage de la
figure 6-8.
Les éléments de liste sur lesquels on a double-cliqué sont transformés en champs de saisie,
initialisés avec le contenu de l’élément (ici, this.props.txt).
Cependant, la saisie dans chaque champ n’est pas prise en compte... C’est l’étape suivante !
67756-React.js-INT.book Page 152 Friday, March 1, 2019 7:15 PM
React.js
152
Figure 6–8
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
super(props);
this.ukey = props.ukey;
this.state = { style : {}, removed : false, modifyOn : false };
}
mouseOver() {
var style = { color : "red", fontStyle : "italic" };
this.setState({style : style });
}
mouseOut() {
var style = { color : "", fontStyle : "" };
this.setState({style : style });
}
handlerRemoveElem() {
this.props.app.removeElem(this); // this : objet de classe Element
}
modifyElem() {
this.setState({ modifyOn : true });
}
handlerChange(event) {
console.log(event.target.value); // Afficher le texte saisi
}
render() {
return (
this.state.removed ? null :
<li style={this.state.style}
onMouseOver={this.mouseOver.bind(this)}
onMouseOut={this.mouseOut.bind(this)}
onDoubleClick={this.modifyElem.bind(this)} >
{ this.state.modifyOn ?
<input type="text" value={this.props.txt}
onChange={this.handlerChange.bind(this)}/> :
<span>{this.props.txt}</span>
}
<button style={{margin:"10px", fontSize:"10px"}}
onClick={this.handlerRemoveElem.bind(this)}
>
Supprimer
</button>
</li>
)
}
}
React.js
154
Le contenu du champ n’est pas modifié malgré la saisie, et seul le dernier caractère introduit
est récupéré dans event.target.value à chaque saisie de caractère. Bien que cela soit
étrange, c’est normal vu le fonctionnement interne de React, qui ne peut modifier l’affichage
que lors d’un changement de state, ce qui n’a pas encore été effectué.
Il faut donc ajouter dans le state la valeur de l’élément dans le champ de saisie, de façon à ce
que lors de chaque modification du champ, cette nouvelle valeur soit répercutée dans
l’attribut value de l’élément <input>. Pour cela, il faut de plus que la valeur affichée ne pro-
vienne plus de this.props.txt (qui est la valeur initiale du champ) mais de this.state.txt
(qui est la valeur réelle du champ à chaque instant, à condition que le state soit mis à jour à
chaque frappe sur le clavier). On introduit pour cela une nouvelle propriété txt dans le state
de la classe Element, qui contiendra en permanence la valeur saisie dans le champ.
this.state = {
style : {},
removed : false,
modifyOn : false,
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
txt : props.txt
};
}
mouseOver() {
var style = { color : "red", fontStyle : "italic" };
this.setState({style : style });
}
mouseOut() {
var style = { color : "", fontStyle : "" };
this.setState({style : style });
}
handlerRemoveElem() {
this.props.app.removeElem(this); // this : objet de classe Element
}
modifyElem() {
this.setState({ modifyOn : true });
}
handlerChange(event) {
console.log(event.target.value);
this.setState({ txt : event.target.value }); // Afficher le texte saisi
}
render() {
return (
this.state.removed ? null :
<li style={this.state.style}
onMouseOver={this.mouseOver.bind(this)}
onMouseOut={this.mouseOut.bind(this)}
onDoubleClick={this.modifyElem.bind(this)} >
{ this.state.modifyOn ?
<input type="text" value={this.state.txt}
onChange={this.handlerChange.bind(this)}/> :
<span>{this.state.txt}</span>
}
<button style={{margin:"10px", fontSize:"10px"}}
onClick={this.handlerRemoveElem.bind(this)}
>
Supprimer
</button>
</li>
)
}
}
On introduit la propriété txt dans le state, initialisée à partir de this.props.txt. Pour que
cette valeur soit affichée dans le champ, on l’indique dans l’attribut value de l’élément
<input> et dans le contenu du <span> associé.
67756-React.js-INT.book Page 156 Friday, March 1, 2019 7:15 PM
React.js
156
Cette valeur est mise à jour par this.setState() lors du traitement de l’événement
onChange.
Comme précédemment, on tape dans le champ de saisie les caractères abcde (figure 6-10).
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Figure 6–10
Les caractères tapés dans le champ sont maintenant visibles, tandis que la Console montre
l’évolution du texte au fur et à mesure de la saisie. Il reste maintenant à gérer l’appui sur la
touche Entrée qui permet de valider le texte saisi.
Remarque
event.charCode n’est pas initialisé si vous l’utilisez dans l’événement onChange, d’où l’obligation
d’utiliser l’un des trois événements précédents (qui eux l’initialisent).
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
React.js
158
render() {
return (
this.state.removed ? null :
<li style={this.state.style}
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
onMouseOver={this.mouseOver.bind(this)}
onMouseOut={this.mouseOut.bind(this)}
onDoubleClick={this.modifyElem.bind(this)} >
{ this.state.modifyOn ?
<input type="text" value={this.state.txt}
onChange={this.handlerChange.bind(this)}
onKeyPress={this.handlerKeyPress.bind(this)}/> :
<span>{this.state.txt}</span>
}
<button style={{margin:"10px", fontSize:"10px"}}
onClick={this.handlerRemoveElem.bind(this)}
>
Supprimer
</button>
</li>
)
}
}
React.js
160
Figure 6–11
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Agrandissement de la fenêtre
Le but sera de gérer l’agrandissement de la fenêtre du navigateur afin de modifier la taille de
la police de caractères qui augmentera à mesure de l’agrandissement (ou réduira si la fenêtre
se rétrécit).
L’intérêt ici est de montrer comment implémenter un événement que React ne prend pas en
charge, dans ce cas l’événement resize géré sur l’objet window du navigateur. Cet événement
est pris en charge en HTML, mais React ne fournit pas la propriété onResize permettant de
le gérer. On doit donc l’implémenter nous-même...
Pour implémenter un nouvel événement non géré par React, on utilise directement les
méthodes de JavaScript addEventListener() et removeEventListener(). Ces méthodes ser-
viront ici à gérer l’événement resize reçu par l’objet window :
• La méthode window.addEventListener() sera implémentée dans la méthode
componentDidMount() définie dans le composant <App>. La méthode
window.addEventListener("resize", callback) permet d’attacher une fonction de call-
back lors de la réception de l’événement resize par l’objet window. La méthode
addEventListener() est implémentée dans la méthode componentDidMount() de la classe
App et elle est donc appelée lors de la création du composant <App>.
67756-React.js-INT.book Page 161 Friday, March 1, 2019 7:15 PM
Remarque
Pour éviter des problèmes de gestion de la mémoire, il faut qu’à chaque appel à une méthode
addEventListener() soit associé un appel à la méthode removeEventListener() correspondante.
React.js
162
modifyElem() {
this.setState({ modifyOn : true });
}
handlerChange(event) {
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
this.state = {
elems : [], // Tableau d’objets { txt, ukey }
style : { fontSize : this.getFontSize() }
};
}
getUniqueKey() {
var key = Math.random() + "";
return key;
}
insertElem() {
var elems = this.state.elems;
var txt = "Element" + (elems.length + 1);
var ukey = this.getUniqueKey();
var elem = { txt : txt, ukey : ukey };
elems.push(elem);
this.setState({ elems : elems });
}
removeElem(objElem) { // Objet de classe Element
var elems = this.state.elems;
elems = elems.filter(function(elem) {
if (objElem.ukey != elem.ukey) return true; // Conserver l’élément
});
this.setState({ elems : elems });
}
modifyElem(objElem, newValue) { // Objet de classe Element
var elems = this.state.elems;
elems = elems.map(function(elem) {
var { txt, ukey } = elem;
if (objElem.ukey == ukey) elem.txt = newValue; // Modifier l’élément
return elem;
});
this.setState({ elems : elems });
}
getFontSize() { // Retourne fontSize en fonction de la hauteur de la fenêtre
var fontSize;
if (window.innerHeight < 150) fontSize = 12;
else if (window.innerHeight < 200) fontSize = 13;
else if (window.innerHeight < 250) fontSize = 15;
else if (window.innerHeight < 300) fontSize = 16;
else if (window.innerHeight < 350) fontSize = 18;
else if (window.innerHeight < 400) fontSize = 20;
else if (window.innerHeight < 450) fontSize = 22;
else if (window.innerHeight < 500) fontSize = 24;
else if (window.innerHeight < 550) fontSize = 30;
else fontSize = 40;
return fontSize + "px";
}
67756-React.js-INT.book Page 164 Friday, March 1, 2019 7:15 PM
React.js
164
handlerResize(event) {
var fontSize = this.getFontSize();
this.setState({ style : { fontSize : fontSize }});
}
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
componentDidMount() {
window.addEventListener("resize", this.handlerResize.bind(this));
}
componentWillUnmount() {
window.removeEventListener("resize", this.handlerResize);
}
render() {
return (
<div>
<button onClick={this.insertElem.bind(this)}>Insérer</button>
<ListeElements elems={this.state.elems} app={this}
style={this.state.style} />
</div>
)
}
}
La méthode getFontSize() définie dans la classe App permet de récupérer une taille de police
en fonction de la hauteur de la fenêtre. Cette taille sera répercutée dans la propriété style du
state associé à la classe App.
Ce style est transmis en tant que propriété (props.style) lors de la création du composant
<ListeElements>, puis transféré de la même façon lors de la création des composants
<Element>.
Remarque
L’emploi de l’opérateur … permet de déstructurer un objet et de regrouper ses propriétés au sein d’un
nouvel objet. En effet, la classe Element gère déjà une propriété style dans son state, et les nouveaux
styles transmis doivent être concaténés avec ceux existants, et non pas les remplacer. L’opérateur … per-
met de réaliser cette opération de façon très simple.
Figure 6–12
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Figure 6–13
67756-React.js-INT.book Page 166 Friday, March 1, 2019 7:15 PM
React.js
166
La propriété fontSize dans le style associé à l’objet props indique bien "15px" (ce qui est ici
la valeur correcte que l’on retrouve dans le state du composant App), mais visiblement cette
propriété fontSize n’est pas répercutée à l’écran. Pourquoi ?
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
En fait, la valeur de l’objet props n’est pas répercutée à l’écran, car le composant <Element>
est déjà créé. React définit la méthode componentWillReceiveProps(props) afin de pouvoir
traiter le cas où un composant déjà créé reçoit de nouvelles props, ce qui est le cas ici.
Implémentons cette méthode dans le composant <Element> et effectuons un appel à
setState()en indiquant le nouveau style (inclus dans l’objet props transmis en paramètres).
render() {
return (
this.state.removed ? null :
<li style={this.state.style}
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
onMouseOver={this.mouseOver.bind(this)}
onMouseOut={this.mouseOut.bind(this)}
onDoubleClick={this.modifyElem.bind(this)} >
{ this.state.modifyOn ?
<input type="text" value={this.state.txt}
onChange={this.handlerChange.bind(this)}
onKeyPress={this.handlerKeyPress.bind(this)}/> :
<span>{this.state.txt}</span>
}
<button style={{margin:"10px", fontSize:"10px"}}
onClick={this.handlerRemoveElem.bind(this)}
>
Supprimer
</button>
</li>
)
}
}
React.js
168
}
insertElem() {
var elems = this.state.elems;
var txt = "Element" + (elems.length + 1);
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
}
}
Figure 6–14
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
7
Gérer les formulaires avec React
Dans les chapitres précédents, nous avons utilisé deux types d’éléments HTML que nous
avons appris à gérer au moyen de React : les boutons et les champs de saisie. Il existe cepen-
dant plusieurs types d’éléments HTML qui peuvent interagir dans nos pages HTML :
• les champs de saisie d’une seule ligne (éléments <input> de type text), déjà étudiés
précédemment ;
• les boutons classiques (éléments <button> ou <input> de type button), également étudiés
précédemment ;
• les champs de saisie multilignes (éléments <textarea>) ;
• les listes de sélection (éléments <select> incluant des éléments <option>) ;
• les boutons radio (éléments <input> de type radio) ;
• les cases à cocher (éléments <input> de type checkbox).
Dans ce chapitre, nous allons étudier ces nouveaux éléments.
React.js
172
<html>
<head>
<script crossorigin
src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin
src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="app"></div>
</body>
<script type="text/babel">
class TextArea extends React.Component {
constructor(props) {
super(props);
this.state = { value : props.value };
}
handlerChange(event) {
this.setState({value : event.target.value});
}
67756-React.js-INT.book Page 173 Friday, March 1, 2019 7:15 PM
render() {
return (
<textarea cols={this.props.cols}
rows={this.props.rows}
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
value={this.state.value}
onChange={this.handlerChange.bind(this)}
/>
)
}
}
ReactDOM.render(
<TextArea cols={40} rows={10} value="Tapez votre texte ici" />,
document.getElementById("app")
);
</script>
</html>
Le fonctionnement d’un champ de saisie multiligne (<textarea>) est similaire à celui d’un
champ <input> d’une seule ligne.
Après avoir affiché le composant et tapé quelques caractères dans le champ de saisie, nous
obtenons l’affichage illustré par la figure 7-1.
Figure 7–1
67756-React.js-INT.book Page 174 Friday, March 1, 2019 7:15 PM
React.js
174
Le texte saisi s’affiche dans le champ, uniquement parce que l’événement onChange a été
implémenté dans la classe et que le state gère la valeur saisie dans le champ...
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
ReactDOM.render(
<TextArea cols={40} rows={10} value="Tapez votre texte ici" focus={true} />,
document.getElementById("app")
);
Figure 7–2
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
La propriété autoFocus est accessible pour tous les éléments React pouvant avoir le focus
(donc pas uniquement les éléments <textarea>).
React.js
176
super(props);
this.state = { value : props.value };
}
handlerChange(event) {
this.setState({value : event.target.value});
}
handlerFocus(event) {
this.setState({value : ""});
}
render() {
return (
<textarea cols={this.props.cols}
rows={this.props.rows}
value={this.state.value}
onChange={this.handlerChange.bind(this)}
onFocus={this.handlerFocus.bind(this)}
autoFocus={this.props.focus}
/>
)
}
}
ReactDOM.render(
<TextArea cols={40} rows={10} value="Tapez votre texte ici" focus={false} />,
document.getElementById("app")
);
Pour bien voir l’effacement du champ lorsqu’il obtient le focus, on met la propriété focus à
false lors de la création du composant <TextArea>.
Affichons le composant avant qu’il obtienne le focus (figure 7-3).
La valeur par défaut du champ est encore affichée...
Nous cliquons ensuite dans le champ de saisie (figure 7-4).
Le contenu du champ de saisie est effacé dès que l’on a cliqué à l’intérieur...
67756-React.js-INT.book Page 177 Friday, March 1, 2019 7:15 PM
Figure 7–3
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Figure 7–4
67756-React.js-INT.book Page 178 Friday, March 1, 2019 7:15 PM
React.js
178
indiquant une fonction de traitement différente selon les endroits où ce composant est utilisé.
Par exemple, on souhaite activer une fonction validTextArea(text) lorsque l’on souhaite
valider le contenu du <textarea>. Le composant <TextArea> aurait alors une nouvelle pro-
priété appelée ici onValid dont la valeur serait {validTextArea} :
La fonction validTextArea(text) est définie dans le code JavaScript. Elle utilise le para-
mètre text indiquant le texte qui a été saisi dans le champ <textarea>. Par exemple, voici sa
définition :
Pour l’instant, la fonction de validation ne fait qu’afficher dans la console le texte indiqué en
paramètre.
Il reste à définir à quel moment la fonction de validation doit être activée. Cela pourrait être :
• lors de la sortie du champ de saisie (événement onBlur) ;
• lors de l’appui d’une combinaison de touches au moment de la saisie (par exemple,
Maj+Entrée) ;
• lors du clic sur un bouton en dehors du champ de saisie (clic sur un bouton Valider).
Examinons ces différentes possibilités dans les paragraphes qui suivent.
handlerChange(event) {
this.setState({value : event.target.value});
}
handlerFocus(event) {
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
this.setState({value : ""});
}
handlerBlur(event) {
var value = event.target.value;
this.props.onValid(value); // Appel de la méthode validTextArea(value)
}
render() {
return (
<textarea cols={this.props.cols}
rows={this.props.rows}
value={this.state.value}
onChange={this.handlerChange.bind(this)}
onFocus={this.handlerFocus.bind(this)}
onBlur={this.handlerBlur.bind(this)}
autoFocus={this.props.focus}
/>
)
}
}
ReactDOM.render(
<TextArea cols={40} rows={10} value="Tapez votre texte ici"
onValid={validTextArea} />,
document.getElementById("app")
);
React.js
180
Figure 7–5
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
handlerKeyPress(event) {
if (event.shiftKey && event.charCode == 13) { // Maj+Entrée
var value = event.target.value;
this.props.onValid(value); // Appel de la méthode validTextArea(value)
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
}
}
render() {
return (
<textarea cols={this.props.cols}
rows={this.props.rows}
value={this.state.value}
onChange={this.handlerChange.bind(this)}
onFocus={this.handlerFocus.bind(this)}
onKeyPress={this.handlerKeyPress.bind(this)}
autoFocus={this.props.focus}
/>
)
}
}
ReactDOM.render(
<TextArea cols={40} rows={10} value="Tapez votre texte ici"
onValid={validTextArea} />,
document.getElementById("app")
);
React.js
182
</div>
)
}
}
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
function validTextArea(text) {
console.log(text);
}
ReactDOM.render(
<TextAreaWithButton cols={40} rows={10} value="Tapez votre texte ici"
onValid={validTextArea} />,
document.getElementById("app")
);
React.js
184
La saisie fonctionne (le champ de saisie se met à jour à chaque frappe sur le clavier) et le texte
Validation s’affiche dans la console lorsque le bouton Valider est cliqué.
Il reste maintenant à récupérer le texte renseigné dans le champ de saisie pour l’afficher dans
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Méthode handlerValid()
handlerValid() {
// console.log("Validation");
this.props.onValid(texte saisi); // Valider le texte saisi
}
)
}
}
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
function validTextArea(text) {
console.log(text);
}
ReactDOM.render(
<TextAreaWithButton cols={40} rows={10} value="Tapez votre texte ici"
onValid={validTextArea} />,
document.getElementById("app")
);
L’instance du composant parent est transmise dans la propriété app lors de la création du
composant enfant <TextArea>.
À chaque modification de la valeur saisie, le state du composant enfant est mis à jour, mais
également le state du composant parent. Le composant parent peut alors utiliser son state lors
de la validation sur le bouton.
Le texte saisi est affiché dans la console lors de chaque clic sur le bouton de validation.
67756-React.js-INT.book Page 186 Friday, March 1, 2019 7:15 PM
React.js
186
Figure 7–7
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
<select>
<option value="1">Element1</option>
<option value="2">Element2</option>
<option value="3">Element3</option>
<option value="4">Element4</option>
<option value="5">Element5</option>
</select>
Note
L’attribut value indiqué pour chaque élément de liste permet d’affecter une valeur qui sera récupérée
lorsque l’élément associé sera sélectionné.
67756-React.js-INT.book Page 187 Friday, March 1, 2019 7:15 PM
React.js
188
this.props.options.map(function(option, index) {
return <option key={index+1} value={index+1}>{option}</option>
})
}
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
</select>
)
}
}
ReactDOM.render(
<Select
options={["Element1", "Element2", "Element3", "Element4", "Element5"]} />,
document.getElementById("app")
);
L’attribut key positionné lors de la création de l’élément <option> est nécessaire car React
l’utilise pour identifier de façon unique chaque élément de la liste. On utilise index+1 (au lieu
de simplement index) afin de commencer la numérotation à 1 et non pas 0 (pour être simi-
laire à la liste HTML précédente).
On affiche ensuite la liste et on sélectionne l’onglet React de la fenêtre (figure 7-9).
Figure 7–9
67756-React.js-INT.book Page 189 Friday, March 1, 2019 7:15 PM
On utilise l’attribut onChange sur l’élément <select> afin d’effectuer le traitement lors de la
sélection d’un nouvel élément dans la liste.
ReactDOM.render(
<Select
options={["Element1", "Element2", "Element3", "Element4", "Element5"]} />,
document.getElementById("app")
);
React.js
190
Figure 7–10
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
})
}
</select>
)
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
}
}
function onSelectElement(value) {
console.log(value);
}
ReactDOM.render(
<Select options={["Element1", "Element2", "Element3", "Element4", "Element5"]}
onSelect={onSelectElement} />,
document.getElementById("app")
);
Attention
Ceci fonctionne en JSX mais pas en HTML (l’attribut defaultValue est inconnu sur l’élément HTML
<select>). Mais on n’écrit pas de code HTML dans les programmes React, donc tout va bien...
On indique dans l’exemple qui suit, l’élément sélectionné au moyen de l’attribut default
dans le composant <Select>. La valeur de l’attribut doit correspondre à l’attribut value d’un
élément mis dans la liste (si ce n’est pas le cas, le premier élément de la liste est sélectionné
par défaut, comme si rien n’était indiqué).
React.js
192
render() {
return (
<select defaultValue={this.props.default}>
{
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
this.props.options.map(function(option, index) {
return <option key={index+1} value={index+1}>{option}</option>
})
}
</select>
)
}
}
ReactDOM.render(
<Select options={["Element1", "Element2", "Element3", "Element4", "Element5"]}
default="5" />,
document.getElementById("app")
);
L’attribut default (ou un autre nom au besoin) est utilisé dans le composant <Select>, mais
c’est l’attribut defaultValue qui doit être utilisé dans l’élément React <select>.
Vérifions que l’élément dont l’attribut value vaut 5 est bien sélectionné par défaut (figure 7-11).
Figure 7–11
67756-React.js-INT.book Page 193 Friday, March 1, 2019 7:15 PM
L’élément 5 est bien celui sélectionné par défaut lors de l’affichage de la liste.
Utilisons les boutons radio afin d’effectuer sur ces éléments les opérations les plus usuelles :
• afficher un groupe de boutons radio (avec un seul composant ou avec deux composants
React) ;
• présélectionner un bouton radio dans le groupe ;
• déclencher une action dès la sélection d’un bouton radio ou à l’aide d’un bouton externe.
var radios = [
{ value : 1, text : "radio1" },
{ value : 2, text : "radio2" },
{ value : 3, text : "radio3" },
{ value : 4, text : "radio4" }
];
ReactDOM.render(
<RadioGroup radios={radios} name="group1" />,
document.getElementById("app")
);
Les boutons radio sont ici mis dans un tableau d’objets { value, text } dans lequel la pro-
priété value correspond à la valeur du bouton lorsqu’il est sélectionné, tandis que la propriété
text représente le texte qui sera affiché pour ce bouton.
La propriété name indique un nom pour le groupe de ces boutons, ce qui permet l’exclusion
mutuelle de ces boutons entre eux (un bouton sélectionné dans un groupe permet de désélec-
tionner les autres boutons du même groupe). Si la propriété name n’est pas indiquée dans un
bouton radio, ce dernier ne participera pas à l’exclusion des autres boutons radio même s’ils
sont visuellement dans le même groupe.
Écrivons le composant <RadioGroup> permettant d’afficher ces boutons radio. Chaque
bouton radio sera composé d’un élément <label> contenant le texte du bouton (élément
<span>) et le bouton radio (élément <input type="radio">).
67756-React.js-INT.book Page 194 Friday, March 1, 2019 7:15 PM
React.js
194
Composant RadioGroup permettant d’afficher les boutons radio d’un même groupe
super(props);
}
render() {
return (
<div>
{
this.props.radios.map((radio, index) => {
return (
<label key={index}>
<span>{radio.text}</span>
<input type="radio" value={radio.value} name={this.props.name} />
<br/>
</label>
)
})
}
</div>
)
}
}
var radios = [
{ value : 1, text : "radio1" },
{ value : 2, text : "radio2" },
{ value : 3, text : "radio3" },
{ value : 4, text : "radio4" }
];
ReactDOM.render(
<RadioGroup radios={radios} name="group1" />,
document.getElementById("app")
);
Figure 7–12
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
React.js
196
<label>
<span>{this.props.text}</span>
<input type="radio" value={this.props.value} name={this.props.name} />
<br/>
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
</label>
)
}
}
var radios = [
{ value : 1, text : "radio1" },
{ value : 2, text : "radio2" },
{ value : 3, text : "radio3" },
{ value : 4, text : "radio4" }
];
ReactDOM.render(
<RadioGroup radios={radios} name="group1" />,
document.getElementById("app")
);
quer l’attribut checked positionné à true. La mise à false de cet attribut désélectionne le
bouton radio.
var radios = [
{ value : 1, text : "radio1" },
{ value : 2, text : "radio2" },
{ value : 3, text : "radio3", checked : true }, // Présélectionné par défaut
{ value : 4, text : "radio4" }
];
Un seul bouton radio dans un même groupe doit posséder l’attribut checked positionné à
true. Les autres boutons radio du groupe peuvent avoir la propriété checked positionnée à
false, voire non indiquée comme ici.
React.js
198
render() {
return (
<div>
{
this.props.radios.map((radio, index) => {
return (
<Radio key={index} text={radio.text} value={radio.value}
name={this.props.name} checked={radio.checked}
/>
)
})
}
</div>
)
}
}
var radios = [
{ value : 1, text : "radio1" },
{ value : 2, text : "radio2" },
{ value : 3, text : "radio3", checked : true },
{ value : 4, text : "radio4" }
];
ReactDOM.render(
<RadioGroup radios={radios} name="group1" />,
document.getElementById("app")
);
Figure 7–13
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
React.js
200
render() {
return (
<div>
{
this.props.radios.map((radio, index) => {
return (
<Radio key={index} text={radio.text} value={radio.value}
name={this.props.name} checked={radio.checked}
/>
)
})
}
</div>
)
}
}
var radios = [
{ value : 1, text : "radio1" },
{ value : 2, text : "radio2" },
{ value : 3, text : "radio3", checked : true },
{ value : 4, text : "radio4" }
];
ReactDOM.render(
<RadioGroup radios={radios} name="group1" />,
document.getElementById("app")
);
L’événement onChange a été implémenté sur l’élément <input> définissant le bouton radio
(dans la classe Radio). La valeur du bouton cliqué est affichée dans la console.
Vérifions si cela fonctionne mieux maintenant (figure 7-14).
Le message d’erreur affiché par React a disparu (vu qu’on a implémenté l’événement
onChange comme il le demandait). Toutefois, les clics sur les autres boutons radio affichent
bien la valeur associée au bouton dans la console, mais le bouton radio ne se sélectionne pas à
l’écran... Pourquoi ?
Pourquoi les boutons radio ne se sélectionnent-ils pas à l’écran lorsqu’ils sont sélectionnés
avec la souris ? N’oublions pas que ce qui est affiché à l’écran est le résultat de l’appel automa-
tique de la méthode render() par React lors de la création des composants. Pour que ce qui
est affiché à l’écran soit modifié (par exemple, suite à un clic sur un autre bouton radio), il
faudrait que la méthode render() soit de nouveau appelée, ce qui ne peut se faire que si l’on
modifie le state. Or, nous n’avons nulle part indiqué le state, dans aucune des deux classes
Radio et RadioGroup.
67756-React.js-INT.book Page 201 Friday, March 1, 2019 7:15 PM
Figure 7–14
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
On va donc indiquer dans le state de la classe Radio, l’état checked (true ou false) du
bouton radio associé à ce composant (this.state.checked). Le clic sur un bouton radio
devra donc mettre à true l’état checked de ce bouton radio, mais devra mettre à false les
états checked des autres boutons radio (un seul bouton radio peut être sélectionné dans le
groupe). Pour réaliser cela, on introduit dans le state associé au composant <RadioGroup> la
propriété radios (this.state.radios) qui contient les valeurs de la variable radios indi-
quant l’état initial des boutons radio.
Lors d’un clic sur un bouton radio, l’état this.state.radios du composant <RadioGroup>
devra être mis à jour, ce qui provoquera un rafraîchissement de l’ensemble des boutons radio
du composant <RadioGroup>.
Afin que le clic sur un bouton radio (composant <Radio>) puisse mettre à jour le state situé
dans le composant parent <RadioGroup>, il faut que le composant parent transmette son ins-
tance au composant fils. Cette transmission d’instance s’effectue dans l’objet props (comme
on l’a déjà fait précédemment), et on nomme par exemple app la propriété transmise.
67756-React.js-INT.book Page 202 Friday, March 1, 2019 7:15 PM
React.js
202
var radios = [
{ value : 1, text : "radio1" },
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
ReactDOM.render(
<RadioGroup radios={radios} name="group1" />,
document.getElementById("app")
);
La mise à jour du state associé à this.state.radios (lors d’un clic sur un bouton radio) provoque
un nouveau render() des boutons radio (méthode render() du composant <RadioGroup>), ce
qui provoque le render() de chaque bouton radio (méthode render() du composant <Radio>).
Remarquez que this.state.checked doit être initialisé dans tous les cas (d’où la mise à
false si props.checked est inexistant), sinon React produit une erreur (lors de la sélection
d’un autre bouton radio) indiquant que le composant passe d’un état uncontrolled à un état
controlled. En fait, cela signifie que tantôt le composant est géré avec le state, tantôt non.
Pour remédier à cela, on initialise le state dans tous les cas.
Toutefois, le clic sur les boutons radio n’est toujours pas pris en compte à l’écran, même si la
fonction de traitement est activée comme on peut le voir dans la console (figure 7-15).
Figure 7–15
67756-React.js-INT.book Page 204 Friday, March 1, 2019 7:15 PM
React.js
204
Les clics sur les boutons sont bien pris en compte, mais l’affichage ne se modifie pas...
La non mise à jour à l’écran des boutons radio sélectionnés s’explique aisément. Nous allons
sélectionner l’onglet React et afficher le dernier composant <Radio> sur lequel on a cliqué
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
On voit que l’objet props possède bien la propriété checked de cet élément à true (les autres
sont à false), mais le problème vient de ce que la propriété this.state.checked de cet élé-
ment reste à false, en contradiction avec sa propriété this.props.checked. La propriété
checked est bien mise à jour pour cet élément, mais pas son state...
En fait, ce comportement est normal. On a déjà vu que la mise à jour de nouvelles propriétés
pour un élément déjà affiché ne provoque pas le rafraîchissement de cet élément (pas de
nouvel appel à la méthode render()), car seule la mise à jour du state le permet. Il faut donc
utiliser la méthode componentWillReceiveProps(newProps) pour être prévenu que de nou-
velles propriétés ont été transmises à un composant, et mettre à jour le state du composant
pour le rafraîchir à l’écran.
On ajoute donc la méthode componentWillReceiveProps(newProps) dans le composant
<Radio>.
67756-React.js-INT.book Page 205 Friday, March 1, 2019 7:15 PM
super(props);
this.state = { checked : props.checked || false };
}
handlerChange(event) {
console.log(event.target.value);
var radios = this.props.app.state.radios;
radios = radios.map((radio, index) => {
if (radio.value == event.target.value) radio.checked = true;
else radio.checked = false;
return radio;
});
this.props.app.setState({radios : radios});
}
componentWillReceiveProps(newProps) {
this.setState({checked : newProps.checked});
}
render() {
return (
<label>
<span>{this.props.text}</span>
<input type="radio" value={this.props.value}
name={this.props.name}
checked={this.state.checked}
onChange={this.handlerChange.bind(this)}
/>
<br/>
</label>
)
}
}
React.js
206
</div>
)
}
}
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
var radios = [
{ value : 1, text : "radio1" },
{ value : 2, text : "radio2" },
{ value : 3, text : "radio3", checked : true },
{ value : 4, text : "radio4" }
];
ReactDOM.render(
<RadioGroup radios={radios} name="group1" />,
document.getElementById("app")
);
La mise à jour de la propriété checked est maintenant transmise au state, ce qui permet la
mise à jour à l’écran.
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
function selectRadio(value) {
console.log(value); // Valeur du bouton radio sélectionné
}
ReactDOM.render(
<RadioGroup radios={radios} name="group1" onSelect={selectRadio} />,
document.getElementById("app")
);
La prise en compte de ce nouvel attribut entraîne des modifications dans les composants
<Radio> et <RadioGroup>.
React.js
208
this.props.app.setState({radios : radios});
this.props.onSelect(event.target.value); // Appel de selectRadio()
}
componentWillReceiveProps(newProps) {
this.setState({checked : newProps.checked});
}
render() {
return (
<label>
<span>{this.props.text}</span>
<input type="radio" value={this.props.value}
name={this.props.name}
checked={this.state.checked}
onChange={this.handlerChange.bind(this)}
/>
<br/>
</label>
)
}
}
var radios = [
{ value : 1, text : "radio1" },
{ value : 2, text : "radio2" },
{ value : 3, text : "radio3", checked : true },
67756-React.js-INT.book Page 209 Friday, March 1, 2019 7:15 PM
function selectRadio(value) {
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
ReactDOM.render(
<RadioGroup radios={radios} name="group1" onSelect={selectRadio} />,
document.getElementById("app")
);
L’appel à la fonction transmise dans l’attribut onSelect, est effectué lors de chaque clic sur un
bouton radio, donc dans la méthode handlerChange().
Cliquons sur différents boutons radio dans la fenêtre (figure 7-18).
Figure 7–18
Le clic sur chaque bouton radio provoque l’appel de la fonction de traitement, ce qui affiche
la valeur du bouton radio dans la console.
67756-React.js-INT.book Page 210 Friday, March 1, 2019 7:15 PM
React.js
210
intègre le bouton de validation avec les boutons radio précédents. Appelons ce nouveau com-
posant <RadioGroupWithButton>. Il s’utilise de la façon suivante :
function validRadio(value) {
console.log(value); // Valeur du bouton radio sélectionné
}
ReactDOM.render(
<RadioGroupWithButton radios={radios} name="group1" onValid={validRadio} />,
document.getElementById("app")
);
L’attribut onValid spécifie une fonction de traitement ayant en paramètre la valeur du bouton
radio sélectionné. Cette fonction de traitement est activée lors du clic sur le bouton de valida-
tion Valider affiché par le composant <RadioGroupWithButton>.
L’attribut onSelect utilisé précédemment est ici supprimé, mais aurait pu être conservé dans
le cas où on souhaite en plus effectuer un traitement lors de la sélection immédiate d’un
bouton radio.
Implémentons cette nouvelle classe RadioGroupWithButton, en plus des classes Radio et
RadioGroup déjà écrites.
Composant RadioGroupWithButton
<label>
<span>{this.props.text}</span>
<input type="radio" value={this.props.value}
name={this.props.name}
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
checked={this.state.checked}
onChange={this.handlerChange.bind(this)}
/>
<br/>
</label>
)
}
}
React.js
212
</div>
)
}
}
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
var radios = [
{ value : 1, text : "radio1" },
{ value : 2, text : "radio2" },
{ value : 3, text : "radio3", checked : true },
{ value : 4, text : "radio4" }
];
function validRadio(value) {
console.log(value); // Valeur du bouton radio sélectionné
}
ReactDOM.render(
<RadioGroupWithButton radios={radios} name="group1" onValid={validRadio} />,
document.getElementById("app")
);
La méthode handlerValid() est activée lors du clic sur le bouton de validation. Elle détecte
le bouton radio éventuellement sélectionné, et appelle la méthode indiquée dans la propriété
onValid du composant.
La méthode forEach(), utilisée sur le tableau radios associé aux boutons radio, permet d’effec-
tuer un traitement pour chaque élément du tableau radios. Elle sert ici à détecter le bouton
radio qui est éventuellement sélectionné et à récupérer la valeur associée (undefined si aucune).
Après avoir sélectionné différents boutons radio et cliqué sur le bouton Valider, on obtient
l’affichage de la figure 7-19.
Les valeurs des boutons radio sélectionnés s’affichent dans la console lors de chaque clic sur le
bouton Valider.
67756-React.js-INT.book Page 213 Friday, March 1, 2019 7:15 PM
Figure 7–19
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
React.js
214
}
}
var checkboxes = [
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
ReactDOM.render(
<CheckBoxGroup checkboxes={checkboxes} />,
document.getElementById("app")
);
Le principe est similaire à celui des boutons radio, mais en plus simple car on n’a plus besoin
de gérer le state dans la classe CheckBoxGroup.
Pour cela, le state de chaque case à cocher est géré directement lors du clic sur celle-ci (via
this.state.checked).
Après sélection et désélection des cases à cocher, nous obtenons ceci (figure 7-20).
Figure 7–20
67756-React.js-INT.book Page 216 Friday, March 1, 2019 7:15 PM
React.js
216
Le state de chaque case à cocher, visible dans l’onglet React, correspond à ce qui est visible à
l’écran.
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
function selectCheckbox(checkbox) {
console.log(checkbox + " selectionne");
}
function unselectCheckbox(checkbox) {
console.log(checkbox + " deselectionne");
}
ReactDOM.render(
<CheckBoxGroup checkboxes={checkboxes}
onSelect={selectCheckbox} onUnselect={unselectCheckbox} />,
document.getElementById("app")
);
return (
<label>
<span>{this.props.text}</span>
<input type="checkbox" value={this.props.value}
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
checked={this.state.checked}
onChange={this.handlerChange.bind(this)}
/>
<br/>
</label>
)
}
}
var checkboxes = [
{ value : 1, text : "check1" },
{ value : 2, text : "check2", checked : true },
{ value : 3, text : "check3", checked : true },
{ value : 4, text : "check4" }
];
function selectCheckbox(checkbox) {
console.log(checkbox + " selectionne");
}
function unselectCheckbox(checkbox) {
console.log(checkbox + " deselectionne");
}
ReactDOM.render(
<CheckBoxGroup checkboxes={checkboxes}
onSelect={selectCheckbox} onUnselect={unselectCheckbox} />,
document.getElementById("app")
);
67756-React.js-INT.book Page 218 Friday, March 1, 2019 7:15 PM
React.js
218
Les propriétés onSelect et onUnselect n’étant pas transmises dans l’objet props lors de la
création des composants <CheckBox>, on utilise la propriété app afin que chaque composant
<CheckBox> puisse accéder à ces propriétés du composant <CheckBoxGroup>.
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Figure 7–21
super(props);
this.state = { checked : props.checked || false };
}
handlerChange(event) {
this.setState({checked : event.target.checked});
var checkboxes =
this.props.app.state.checkboxes.map(function(checkbox, index) {
if (checkbox.value == event.target.value)
checkbox.checked = event.target.checked; // Nouvelle valeur
return checkbox;
});
this.props.app.setState({checkboxes : checkboxes});
}
render() {
return (
<label>
<span>{this.props.text}</span>
<input type="checkbox" value={this.props.value}
checked={this.state.checked}
onChange={this.handlerChange.bind(this)}
/>
<br/>
</label>
)
}
}
React.js
220
var checkboxes = [
{ value : 1, text : "check1" },
{ value : 2, text : "check2", checked : true },
{ value : 3, text : "check3", checked : true },
{ value : 4, text : "check4" }
];
function validCheckboxes(checkboxes) {
console.log(checkboxes);
}
ReactDOM.render(
<CheckBoxGroupWithButton checkboxes={checkboxes} onValid={validCheckboxes} />,
document.getElementById("app")
);
Figure 7–22
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
React.js
222
disposition l’objet refs, accessible dans la classe associée au composant par this.refs. Cela
signifie que cet objet this.refs n’est accessible que dans les composants créés avec une
classe, et n’est pas disponible dans les composants créés avec des fonctions.
L’objet this.refs est un tableau qui contiendra tous les attributs ref positionnés dans le code
JSX de notre composant. Il suffit donc d’écrire un attribut ref (valant une chaîne de carac-
tères) dans un élément JSX, et l’élément DOM correspondant sera stocké dans le tableau
this.refs du composant.
L’élément JSX sur lequel on positionne l’attribut ref doit correspondre à un élément JSX
écrit en HTML, et non pas à un composant React créé via une classe (sinon aucun élément
du DOM réel ne lui correspond directement).
Remarque
Le cas où l’attribut ref est positionné sur un composant React créé par une classe est traité dans la sec-
tion suivante.
Pour illustrer cela, écrivons un programme React affichant deux listes d’éléments dans un
composant <App>. Nous avons inséré des attributs ref sur certains éléments HTML des
listes. Lorsque le composant <App> est prêt (c’est-à-dire lorsque sa méthode
componentDidMount() est appelée), cela signifie que le code HTML du composant a été
affiché et les éléments HTML sont créés. Dans la méthode componentDidMount(), l’objet
this.refs contient les références vers les éléments DOM associés.
<ul ref="ref2">
<li ref="ref3">Element11</li>
<li>Element12</li>
<li>Element13</li>
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
<li>Element14</li>
<li>Element15</li>
</ul>
</div>
)
}
}
ReactDOM.render(
<App />,
document.getElementById("app")
);
Figure 7–23
Nous affichons les références associées aux trois éléments HTML sur lesquels les attributs
refsont positionnés.
67756-React.js-INT.book Page 224 Friday, March 1, 2019 7:15 PM
React.js
224
Maintenant que nous avons affiché le contenu de l’objet this.refs, que peut-on faire avec ?
Chacun des éléments de ce tableau est en fait un élément DOM classique, sur lequel on peut
effectuer toutes les manipulations du DOM souhaitées. Ces dernières peuvent être réalisées
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
<html>
<head>
<script crossorigin
src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin
src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<div id="app"></div>
</body>
<script type="text/babel">
<li>Element12</li>
<li>Element13</li>
<li>Element14</li>
<li>Element15</li>
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
</ul>
</div>
)
}
}
ReactDOM.render(
<App />,
document.getElementById("app")
);
</script>
</html>
La bibliothèque jQuery est incluse à l’aide de la balise <script>, et les instructions jQuery
sont insérées dans la méthode componentDidMount() afin que les éléments DOM soient
accessibles.
Figure 7–24
67756-React.js-INT.book Page 226 Friday, March 1, 2019 7:15 PM
React.js
226
L’élément ayant la référence ref="ref3" a bien son style modifié, mais l’on peut voir dans
l’onglet React que rien n’indique que cette modification a eu lieu... D’où les risques potentiels
d’erreurs entre le DOM virtuel géré par React et le DOM réel modifié via JavaScript.
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
componentDidMount() {
console.log(this.refs);
$(this.refs.ref3).css("font-size", "20px").css("color", "red");
$(this.refs.ref1).append("<li>Element6</li>");
}
On insère un nouvel élément de liste <li> dans la première liste affichée (figure 7-25).
Figure 7–25
L’élément de liste Element6 apparaît bien à l’écran, mais les éléments React affichés dans
l’onglet React ne reflètent pas du tout cette nouvelle liste !
67756-React.js-INT.book Page 227 Friday, March 1, 2019 7:15 PM
d’un composant (qui doit être défini sous forme de classe, sinon this.refs n’existe pas).
Écrivons une liste d’éléments en utilisant le composant <Element>. Nous indiquons l’attribut
ref sur le premier élément de la liste.
ReactDOM.render(
<App />,
document.getElementById("app")
);
L’attribut ref est ici utilisé à deux emplacements : sur l’élément <ul> et sur le premier com-
posant <Element>. Ces deux références sont stockées dans this.refs, qui est affiché dans la
console par la méthode componentDidMount().
67756-React.js-INT.book Page 228 Friday, March 1, 2019 7:15 PM
React.js
228
Figure 7–26
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
La valeur ref1 est associée à l’élément <ul>, tandis que la valeur ref2 est associée à un objet
de classe Element.
L’intérêt ici est de permettre à un composant parent (ici, <App>) d’accéder à un composant
enfant (ici, <Element>), grâce à la référence indiquée sur le composant enfant. Supposons que
l’on veuille modifier le texte de l’élément affiché dans ce composant. Comme le texte du
composant <Element> est dans le state (dans this.state.elem), on peut utiliser la méthode
setState() sur ce composant <Element>.
componentDidMount() {
console.log(this.refs);
this.refs.ref2.setState({elem : "Nouvel Element1"});
}
render() {
return (
<div>
<ul ref="ref1">
<Element elem="Element1" ref="ref2"></Element>
<Element elem="Element2"></Element>
<Element elem="Element3"></Element>
<Element elem="Element4"></Element>
<Element elem="Element5"></Element>
</ul>
</div>
)
}
}
ReactDOM.render(
<App />,
document.getElementById("app")
);
React.js
230
Figure 7–27
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
React et Ajax
Ajax est un concept permettant de mettre à jour une partie de la page HTML affichée en effec-
tuant une requête au serveur. Ce concept est très utilisé de nos jours dans la plupart des sites
web, car il permet une mise à jour dynamique de la page sans avoir à la recharger totalement.
React n’intègre pas une API permettant d’effectuer des requêtes Ajax, mais il est possible
d’utiliser d’autres API fournies par d’autres bibliothèques, voire d’utiliser l’API interne du
navigateur.
Nous étudions ici ces deux possibilités :
• utilisation de l’API Ajax fournie par jQuery (en utilisant la méthode $.ajax()) ;
• utilisation de l’API interne du navigateur (en utilisant la méthode fetch()).
Dans ces deux cas, on utilise un serveur PHP qui retourne une liste d’éléments au format
JSON (tout autre serveur fonctionnerait selon le même principe).
Le but sera de récupérer cette liste d’éléments sur le serveur, puis de l’afficher dans la page
HTML au moyen de React.
67756-React.js-INT.book Page 231 Friday, March 1, 2019 7:15 PM
Le programme PHP qui retourne la liste est le suivant (fichier action.php). Il est volontaire-
ment très simple car le but ici n’est pas d’écrire des choses complexes côté serveur, mais plutôt
de montrer comment les récupérer et les utiliser ensuite avec React.
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
<?php
$result = array(
array("text"=>"Element1"),
array("text"=>"Element2"),
array("text"=>"Element3"),
array("text"=>"Element4"),
array("text"=>"Element5")
);
echo json_encode($result);
?>
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Une fois la bibliothèque jQuery incluse, le code des composants incluant l’appel Ajax est le
suivant :
67756-React.js-INT.book Page 232 Friday, March 1, 2019 7:15 PM
React.js
232
super(props);
this.state = { elem : props.elem };
}
render() {
return <li>{this.state.elem.text}</li>
}
}
ReactDOM.render(
<App />,
document.getElementById("app")
);
La méthode done() chaînée avec l’appel Ajax est exécutée si l’appel Ajax réussit (une réponse
du serveur a été fournie). Le serveur retourne une chaîne de caractères que l’on transforme en
objet JSON grâce à la méthode JSON.parse() de JavaScript. Le tableau d’objets récupérés est
67756-React.js-INT.book Page 233 Friday, March 1, 2019 7:15 PM
exactement au format { text : "valeur" } utilisé par le composant <Element> (le compo-
sant <Element> récupère la propriété text et l’affiche dans la méthode render()).
La méthode fail() est également chaînée avec l’appel Ajax. Elle est utilisée dans le cas où
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
React.js
234
Le principe de l’appel Ajax avec fetch(url) est le suivant : une fois la méthode fetch()
appelée, un objet response est fourni dans une fonction de callback chaînée grâce à la
méthode then(callback) de JavaScript. Cet objet response est transformé en objet JSON au
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
moyen de la méthode response.json() puis est retourné par la fonction pour être exploité
par une autre fonction de callback également chaînée grâce à then(callback).
On a donc l’enchaînement successif de trois méthodes JavaScript pour utiliser fetch(url) :
Utilisation de fetch(url)
fetch(url).then(callback).then(callback)
L’utilisation dans le programme React est le suivant : les composants React utilisés sont les
mêmes que précédemment (<Element> et <App>), et l’appel Ajax est effectué dans la méthode
componentDidMount() du composant <App>.
Bien entendu, l’inclusion d’une bibliothèque externe telle que jQuery est ici non nécessaire.
render() {
return (
<ul>
{
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
this.state.elems.map(function(elem, index){
return <Element key={index} elem={elem}></Element>
})
}
</ul>
)
}
}
ReactDOM.render(
<App />,
document.getElementById("app")
);
La seconde méthode then() utilise deux fonctions de callback : la première est celle appelée
en cas de succès de l’appel Ajax sur le serveur, la seconde est celle appelée en cas d’erreur.
Remarquez l’utilisation de la notation ES6 pour indiquer les fonctions de traitement. En
effet, comme on doit conserver la valeur de this, on utilise la notation ES6 qui le permet.
Figure 7–29
67756-React.js-INT.book Page 236 Friday, March 1, 2019 7:15 PM
React.js
236
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
8
Utiliser create-react-app pour
créer une application React
Jusqu’à présent, nous avons utilisé un seul fichier HTML (contenant également du code
JavaScript) pour écrire notre code React. Cette approche est simple pour expliquer le fonc-
tionnement de React à travers quelques lignes de code concentrées dans un seul fichier, mais
il ne s’agit pas d’une approche professionnelle permettant d’écrire de nombreux composants
(a fortiori pour une équipe de développeurs de plusieurs personnes).
L’équipe qui a conçu React a donc développé un programme permettant de créer une arbores-
cence de fichiers qui contiendront le code de notre application. Ce programme est un module
npm et nécessite d’avoir installé Node (qui inclut la commande npm) sur la machine qui l’utilise.
node -v
67756-React.js-INT.book Page 238 Friday, March 1, 2019 7:15 PM
React.js
238
La figure 8-1 illustre un exemple de résultat obtenu (si Node est déjà installé, sinon on
obtient un message d’erreur).
Figure 8–1
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
L’option -g utilisée ici permet d’installer ce module de façon globale sur notre machine, per-
mettant ainsi de pouvoir accéder à la commande create-react-app (fournie par le module
installé) à partir de tous les répertoires de notre machine (et non pas seulement depuis le
répertoire actuel d’où est tapée cette commande).
Une fois la commande tapée, les modules (packages) composant l’application s’installent
automatiquement (figure 8-2).
Figure 8–2
Les modules composant l’application create-react-app sont installés dans les répertoires de
notre machine, rendant l’application create-react-app accessible.
Tapons la commande suivante pour vérifier que la commande est accessible.
67756-React.js-INT.book Page 239 Friday, March 1, 2019 7:15 PM
create-react-app -v
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Figure 8–3
create-react-app reactapp
Cette commande crée le répertoire indiqué (ici reactapp), dans le répertoire actuel à partir
duquel on tape la commande.
Dès le lancement de la commande, les modules nécessaires sont téléchargés (figure 8-4).
L’application React est en cours de création...
Après quelques minutes, l’écran suivant apparaît, indiquant le mode d’utilisation des fichiers
créés (figure 8-5).
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
240
Figure 8–5
Figure 8–4
React.js
67756-React.js-INT.book Page 240 Friday, March 1, 2019 7:15 PM
67756-React.js-INT.book Page 241 Friday, March 1, 2019 7:15 PM
cd reactapp
npm start
Figure 8–6
La fenêtre affichée correspond au programme par défaut créé par la commande create-
react-app.
React.js
242
Le dossier reactapp contient tous les programmes nécessaires pour exécuter l’URL indiquée,
comprenant également le serveur web. Ce dossier reactapp est organisé sous forme de réper-
toires comprenant :
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Figure 8–8
Répertoire public de l’application
(fichier index.html)
Figure 8–9
Répertoire src de l’application
(fichiers .css et .js).
Le fichier principal de notre application est index.html. C’est lui qui doit s’exécuter lors du
démarrage de l’application (lorsque l’on accède à l’URL http://localhost:3000).
Fichier public/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1,
shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<!—
manifest.json provides metadata used when your web app is added to the
homescreen on Android.
See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<!—
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
React.js
244
La ligne la plus importante du fichier est celle qui définit <div id="root"></div> car l’on
sait que React utilise un élément <div> de la page HTML dans lequel il affiche le rendu du
composant React principal. Ce composant React est celui de l’application dans son ensemble,
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
qui contient les autres composants. Ce composant sera affiché dans le <div> créé ici.
Lors du chargement du fichier index.html, le fichier src/index.js est également chargé
(sans avoir à l’indiquer dans le code HTML), et contient finalement le code React de notre
application. Cette arborescence (répertoires public et src), ainsi que les noms des fichiers
utilisés (index.html et index.js) sont à conserver si l’on modifie les codes sources de l’appli-
cation par défaut, car sinon rien ne fonctionnera.
Fichier src/index.js
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: http://bit.ly/CRA-PWA
serviceWorker.unregister();
Fichier src/index.css
body {
margin: 0;
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
monospace;
}
Fichier src/App.js
React.js
246
);
}
}
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Chaque composant importe les fichiers qui lui sont nécessaires, ici les modules permettant
d’utiliser les objets React et React.Component. Remarquez l’utilisation des objets déstructurés
en écrivant { Component }, qui signifie qu’il est possible d’utiliser Component comme nom de
classe dans le code au lieu de React.Component.
Plutôt que d’écrire les lignes :
Fichier src/App.css
.App {
text-align: center;
}
.App-logo {
animation: App-logo-spin infinite 20s linear;
height: 40vmin;
}
67756-React.js-INT.book Page 247 Friday, March 1, 2019 7:15 PM
.App-header {
background-color: #282c34;
min-height: 100vh;
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
Le dernier fichier analysé ici est le fichier src/App.test.js. Il permet d’effectuer le test du
composant <App>. Pour exécuter le test, il faut introduire la commande npm test depuis
l’interpréteur de commandes.
nmp test
Figure 8–10
67756-React.js-INT.book Page 248 Friday, March 1, 2019 7:15 PM
React.js
248
faut indiquer les fichiers de notre application réelle (sinon c’est l’application par défaut qui
s’exécute).
Prenons l’exemple de l’application de gestion de liste d’éléments créée au chapitre 6. On avait
utilisé trois composants : <App>, <ListeElements> et <Element>. Le but ici est de créer un
fichier pour chaque composant en utilisant la structure précédente.
getFontSize() {
var fontSize;
if (window.innerHeight < 150) fontSize = 12;
else if (window.innerHeight < 200) fontSize = 13;
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
React.js
250
<ul>
{
this.props.elems.map((elem, index) => {
var { ukey, txt } = elem;
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
handlerKeyPress(event) {
if (event.charCode == 13) {
this.setState({ modifyOn : false });
this.props.app.modifyElem(this, event.target.value);
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
}
}
componentWillReceiveProps(props) {
this.setState({ style : props.style });
}
render() {
return (
this.state.removed ? null :
<li style={this.state.style}
onMouseOver={this.mouseOver.bind(this)}
onMouseOut={this.mouseOut.bind(this)}
onDoubleClick={this.modifyElem.bind(this)} >
{ this.state.modifyOn ?
<input type="text" value={this.state.txt}
onChange={this.handlerChange.bind(this)}
onKeyPress={this.handlerKeyPress.bind(this)}/> :
<span>{this.state.txt}</span>
}
<button style={{margin:"10px", fontSize:"10px"}}
onClick={this.handlerRemoveElem.bind(this)}
>
Supprimer
</button>
</li>
)
}
}
Fichier src/index.js
React.js
252
Figure 8–11
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Notez que la page est rechargée à chaque sauvegarde d’un des fichiers du serveur, ce qui est
bien pratique pour ne pas recharger manuellement la page à chaque fois.
Figure 8–12
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Une fois la commande npm run build tapée, le répertoire build est créé contenant les fichiers
utilisables en mode production.
Figure 8–13
De plus, il est possible de tester immédiatement ces fichiers en suivant les recommandations
affichées sur l’écran de la fenêtre de commandes :
Une fois la commande serve -s build introduite, le serveur s’affiche dans la fenêtre de com-
mandes (figure 8-14).
67756-React.js-INT.book Page 254 Friday, March 1, 2019 7:15 PM
React.js
254
Figure 8–14
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
React.js
256
Classe Element qui vérifie que la propriété elem reçue est bien un objet (fichier src/Element.js)
Element.propTypes = {
elem : PropTypes.object
};
La propriété elem est un objet possédant la propriété text. On définit donc la propriété elem
dans l’objet Element.PropTypes valant PropTypes.object.
Le commentaire contenant eslint permet de ne pas avoir l’avertissement indiquant que le
constructeur écrit est vide (en dehors de l’appel du constructeur parent), car le serveur utilisé
par create-react-app affiche ce message pour nous prévenir d’un éventuel oubli.
Classe App qui utilise la classe Element pour afficher cinq éléments de liste (fichier src/App.js)
elems.map(function(elem, index){
return <Element key={index} elem={elem}></Element>
})
}
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
</ul>
)
}
}
La propriété elem transmise au composant <Element> est bien un objet ayant une propriété
text (comme défini dans le tableau elems).
React.js
258
Element.propTypes = {
elem : PropTypes.string
};
On fait exprès de faire une erreur de type, afin de voir quelle va être la réaction de React lors
de l’affichage de la page.
Affichons de nouveau l’URL http://localhost:3000 (en fait, elle se réaffiche à nouveau toute
seule car le serveur rafraîchit l’affichage à chaque modification de fichier).
Figure 8–17
Un message d’erreur est affiché dans la console (détecté grâce au module prop-types).
67756-React.js-INT.book Page 259 Friday, March 1, 2019 7:15 PM
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
9
Redux
Redux est une bibliothèque JavaScript indépendante de React, mais qui s’utilise beaucoup
avec celui-ci.
• Avec React, elle permet de simplifier la gestion des états (state) des composants d’une
application, en permettant une gestion centralisée de tous les états.
• Sans React, elle s’utilise également dans des applications pour lesquelles on souhaite gérer
les états (comme nous l’avons fait avec React via l’objet state).
Afin de comprendre le fonctionnement de la bibliothèque Redux, on l’utilise dans ce chapitre
indépendamment de React. Son utilisation avec React sera étudiée dans le chapitre suivant.
But de Redux
Redux permet de faciliter la gestion des états. Dans les précédents chapitres, nous avons vu
que tous les composants React (uniquement ceux créés par une classe dérivant de
React.Component) possédent une propriété state qui reflète l’état du composant. Cet état
sert (entre autres) à afficher le composant. Toute modification du composant affiché ne peut
se faire qu’en modifiant l’état.
Parfois, on est obligé de mettre à jour l’état d’un autre composant, ce qui est assez complexe à
faire car il faut avoir accès à cet autre composant. De plus, on n’a pas accès à un état global de
toute l’application, mais uniquement aux états des composants qui la constitue.
67756-React.js-INT.book Page 260 Friday, March 1, 2019 7:15 PM
React.js
260
L’idée de Redux est de centraliser la gestion des états dans un objet unique appelé store, qui
centralise tous les états de tous les composants. Cet objet store (unique pour toute l’applica-
tion) est géré par les méthodes de Redux.
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Installation de Redux
Redux est un module npm qui s’installe au moyen de la commande npm install redux.
Même s’il est mis en œuvre ici sans React, on utilise l’arborescence créée par create-react-
app dans le répertoire react-app (voir chapitre précédent) afin de bénéficier de la structure
installée (en particulier la gestion des modules).
Placez-vous dans le répertoire reactapp et saisissez la commande npm install redux.
cd reactapp
npm install redux
Figure 9–1
Redux
261
CHAPITRE 9
console.log(store);
L’objet store retourné par createStore() possède les méthodes dispatch(), getState(),
replaceReducer() et subscribe(). Ces méthodes permettent le fonctionnement de Redux.
67756-React.js-INT.book Page 262 Friday, March 1, 2019 7:15 PM
React.js
262
Fonctionnement de Redux
La méthode createStore() retourne un objet store pour conserver et gérer l’état de l’appli-
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
cation. Celui-ci ne peut être lu et mis à jour qu’à travers les méthodes suivantes, fournies sur
l’objet store.
• La méthode store.dispatch(action) qui permet d’effectuer une modification de l’état,
en fonction de l’action indiquée. En effet, seules les actions permettent d’effectuer une
modification de l’état. Par exemple, une action pourrait être « Ajouter cet élément dans la
liste » ou « Retirer le deuxième élément de la liste ».
La différence avec React est que la modification de l’état n’est pas faite directement en
indiquant sa valeur (par this.setState()), mais plutôt en exécutant une action qui
provoquera la modification de l’état (par store.dispatch(action)).
• La méthode store.getState() permet de récupérer sous forme d’objet l’état (stocké dans
l’objet store). Cette méthode store.getState() ressemble au fonctionnement de l’objet
this.state utilisé dans React, à la différence qu’elle retourne l’état de toute l’application
et pas seulement celui qui est associé à un composant.
• La méthode store.subscribe(listener) permet d’effectuer un traitement lors de
chaque action. Le traitement est effectué dans la fonction de callback listener().
Globalement, on voit donc que l’on a des actions qui mettent à jour l’état et que l’on peut
« écouter » les éventuels changements d’état lorsque les actions sont exécutées.
La mise à jour de l’état est effectuée suite aux actions « dispatchées », mais la procédure de
mise à jour de l’état est centralisée dans la fonction de callback indiquée en paramètre de la
fonction createStore(reducer). Le reducer (méthode de la forme reducer(state,
action)) est donc une partie importante de l’application car il permet d’indiquer comment
l’état est mis à jour (en fonction de l’ancien état et de l’action effectuée).
Redux
263
CHAPITRE 9
Une action possède des paramètres qui la décrivent. Ainsi, pour les actions précédentes, on
pourrait avoir comme paramètres :
• ajouter un nouvel élément en fin de liste : description de l’élément ;
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
// Actions de suppression
var remove_elem_1 = { type : REMOVE_ELEM, index : 3 };
var remove_elem_2 = { type : REMOVE_ELEM, index : 2 };
// Action d’inversion
var revert_list_1 = { type : REVERT_LIST };
// Actions de recherche
var find_tag_1 = { type : FIND_TAG, tag : "Element3" };
var find_tag_2 = { type : FIND_TAG, tag : "Element4" };
Les types d’actions sont ici définis sous forme de constantes, puis chaque action est décrite
avec ses paramètres. Seul l’attribut type est présent dans chaque action, ce qui permet de
savoir quel est le type de chaque action.
De plus, comme on peut avoir plusieurs actions d’un même type (par exemple add_elem_1,
add_elem_2, etc.), il est plus simple de créer une fonction qui construit l’action, en indiquant
les propriétés de l’action dans les paramètres de la fonction. Ainsi, pour remplacer les actions
définies précédemment, on aurait les créateurs d’actions suivants.
67756-React.js-INT.book Page 264 Friday, March 1, 2019 7:15 PM
React.js
264
// Créateurs d’actions
function add_elem(elem) {
return {
type : ADD_ELEM,
elem : elem
}
}
function remove_elem(index) {
return {
type : REMOVE_ELEM,
index : index
}
}
function revert_list() {
return {
type : REVERT_LIST
}
}
function find_tag(tag) {
return {
type : FIND_TAG,
tag : tag
}
}
// Actions de suppression
var remove_elem_1 = remove_elem(3);
var remove_elem_2 = remove_elem(2);
// Action d’inversion
var revert_list_1 = revert_list();
// Actions de recherche
var find_tag_1 = find_tag("Element3");
var find_tag_2 = find_tag("Element4");
67756-React.js-INT.book Page 265 Friday, March 1, 2019 7:15 PM
Redux
265
CHAPITRE 9
Chaque créateur d’action retourne une action, selon les paramètres indiqués. Les actions sont
ensuite créées en utilisant le créateur d’action associé.
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
createStore(function(state, action) {
console.log("state =", state, "action =", action);
return state; // Par défaut, on retourne l’état actuel
});
Le rôle d’un reducer étant de retourner le nouvel état, il est normal de retourner quelque
chose, ici l’état actuel. Si rien n’est retourné, Redux considérera que le nouvel état était de
valeur undefined.
Il est bien sûr possible d’écrire le reducer sous la forme d’une fonction externe, non directe-
ment intégrée dans l’appel à la fonction createStore().
67756-React.js-INT.book Page 266 Friday, March 1, 2019 7:15 PM
React.js
266
createStore(reducer);
Le reducer est ici défini en tant que fonction externe et il est utilisé en paramètre de la fonc-
tion createStore(reducer).
Figure 9–3
Le reducer est appelé lors de l’initialisation, à l’aide d’une action interne à Redux, tandis que
l’état est undefined vu que l’on ne l’a pas encore défini.
67756-React.js-INT.book Page 267 Friday, March 1, 2019 7:15 PM
Redux
267
CHAPITRE 9
const stateInit = {
elems : [], // Éléments de la liste
revert : false, // true si la liste est inversée
find : {
tag : "", // Tag à rechercher
elems : [] // Éléments contenant le tag recherché
}
}
Il reste à écrire le reducer qui provoque les modifications dans l’état en fonction des actions
qui se produisent.
const stateInit = {
elems : [], // Éléments de la liste
revert : false, // true si la liste est inversée
67756-React.js-INT.book Page 268 Friday, March 1, 2019 7:15 PM
React.js
268
find : {
tag : "", // Tag à rechercher
elems : [] // Éléments contenant le tag recherché
}
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Remarque
Pour chaque action, l’état actuel n’est jamais modifié, mais uniquement la variable locale newState qui
est ensuite retournée par le reducer.
Le statut de départ de l’état est initialisé dans la définition de la fonction, au moyen des fonctionnalités
de ES6. On voit ici l’intérêt de traiter le cas de l’action inconnue dans le reducer, ce qui permet de prendre
en compte l’action d’initialisation interne de Redux.
67756-React.js-INT.book Page 269 Friday, March 1, 2019 7:15 PM
Redux
269
CHAPITRE 9
quoi ce premier objet transmis est un objet vide { }, de façon à ne pas modifier un objet uti-
lisé. Le résultat de la fusion est retourné par la méthode.
De plus, on aurait aussi pu utiliser une autre forme d’écriture en ES6, en utilisant la déstruc-
turation des objets ES6.
Ainsi, au lieu d’écrire :
Les propriétés de l’objet state sont fusionnées dans un nouvel objet avec le tableau elems.
const stateInit = {
elems : [], // Éléments de la liste
revert : false, // true si la liste est inversée
find : {
tag : "", // Tag à rechercher
67756-React.js-INT.book Page 270 Friday, March 1, 2019 7:15 PM
React.js
270
// créateurs d’actions
function add_elem(elem) {
return {
type : ADD_ELEM,
elem : elem
}
}
67756-React.js-INT.book Page 271 Friday, March 1, 2019 7:15 PM
Redux
271
CHAPITRE 9
function remove_elem(index) {
return {
type : REMOVE_ELEM,
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
index : index
}
}
function revert_list() {
return {
type : REVERT_LIST
}
}
function find_tag(tag) {
return {
type : FIND_TAG,
tag : tag
}
}
// Actions d’ajout
store.dispatch(add_elem("Element1"));
store.dispatch(add_elem("Element2"));
store.dispatch(add_elem("Element3"));
store.dispatch(add_elem("Element4"));
store.dispatch(add_elem("Element5"));
// Action d’inversion
store.dispatch(revert_list());
// Actions de recherche
store.dispatch(find_tag("Element5"));
store.dispatch(find_tag("Element2"));
// Actions de suppression
store.dispatch(remove_elem(3));
store.dispatch(remove_elem(2));
React.js
272
Figure 9–4
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Redux
273
CHAPITRE 9
store.subscribe(function() {
console.log(store.getState()); // Afficher le nouvel état
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
});
// Actions d’ajout
store.dispatch(add_elem("Element1"));
store.dispatch(add_elem("Element2"));
store.dispatch(add_elem("Element3"));
store.dispatch(add_elem("Element4"));
store.dispatch(add_elem("Element5"));
// Action d’inversion
store.dispatch(revert_list());
// Actions de recherche
store.dispatch(find_tag("Element5"));
store.dispatch(find_tag("Element2"));
// Actions de suppression
store.dispatch(remove_elem(3));
store.dispatch(remove_elem(2));
On indique ci-après le contenu de chaque fichier. Commençons par le fichier des constantes
d’actions.
React.js
274
Chaque constante est exportée de façon à pouvoir être utilisée dans un autre module.
Le fichier src/actions.js permettant de définir les actions utilise le fichier définissant les
constantes précédentes. Pour importer ces constantes à partir du fichier actions_types.js,
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Il suffit d’énumérer la liste des constantes d’actions qui sont ainsi importées.
Toutefois, cette syntaxe pose un problème dans le cas où on ajoute des nouvelles actions, car il
faut mettre à jour la liste importée. Il serait bien de ne pas avoir à répéter cette liste lors de
chaque import des constantes dans un nouveau fichier.
La syntaxe de l’instruction import le permet, en définissant un espace de nom pour les don-
nées importées. Ainsi, pour importer les constantes du fichier actions_types.js dans le
module actions.js, en utilisant l’espace de nom ACTIONS (ou tout autre nom), on écrit le
code suivant.
Import des constantes d’actions en utilisant l’espace de nom ACTIONS (fichier src/actions.js)
L’espace de nom ACTIONS implique d’utiliser les données importées en les préfixant de
"ACTIONS.". Par exemple, on écrira ACTIONS.ADD_ELEM pour utiliser la constante ADD_ELEM.
Le fichier actions.js peut alors s’écrire ainsi.
// Créateurs d’actions
export function add_elem(elem) {
return {
type : ACTIONS.ADD_ELEM,
elem : elem
}
}
Redux
275
CHAPITRE 9
Le type des actions est préfixé de l’espace de nom ACTIONS, et chaque fonction définissant
une action est exportée (pour pouvoir être utilisée dans un autre module).
Le fichier du reducer est le suivant.
const stateInit = {
elems : [],
revert : false,
find : {
tag : "",
elems : []
}
}
React.js
276
elems.reverse();
newState = Object.assign({}, state, {elems : elems, revert : !revert});
}
else if (action.type == ACTIONS.FIND_TAG) {
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
On importe les constantes d’actions au moyen de l’import avec l’espace de nom ACTIONS (ou
tout autre nom), puis cet espace de nom est utilisé dans toutes les utilisations des constantes
d’actions.
De plus, la fonction du reducer est exportée (export default) de façon à être utilisée lors de
l’instruction createStore(reducer).
Il reste à écrire le fichier src/index.js qui utilise les précédents fichiers. Il est beaucoup plus
court maintenant que les autres fonctionnalités sont externalisées, et il se concentre sur le
traitement principal.
Fichier src/index.js
store.subscribe(function() {
console.log(store.getState()); // Afficher le nouvel état
});
// Actions d’ajout
store.dispatch(ACTIONS.add_elem("Element1"));
store.dispatch(ACTIONS.add_elem("Element2"));
store.dispatch(ACTIONS.add_elem("Element3"));
store.dispatch(ACTIONS.add_elem("Element4"));
store.dispatch(ACTIONS.add_elem("Element5"));
67756-React.js-INT.book Page 277 Friday, March 1, 2019 7:15 PM
Redux
277
CHAPITRE 9
// Action d’inversion
store.dispatch(ACTIONS.revert_list());
// Actions de recherche
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
store.dispatch(ACTIONS.find_tag("Element5"));
store.dispatch(ACTIONS.find_tag("Element2"));
// Actions de suppression
store.dispatch(ACTIONS.remove_elem(3));
store.dispatch(ACTIONS.remove_elem(2));
React.js
278
Conclusion
Dans ce chapitre, nous avons étudié le module Redux indépendamment de React.
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
10
React et Redux
Le chapitre précédent a montré comment utiliser Redux dans une application, indépendam-
ment de React.
Il reste à associer Redux à une application React. Nous procéderons en deux étapes pour
comprendre le fonctionnement :
• d’abord en utilisant Redux directement avec React (dans ce chapitre) ;
• ensuite en utilisant le nouveau module "react-redux" qui permet de simplifier le code à
écrire (dans le chapitre suivant).
Voyons tout d’abord l’utilisation de Redux directement avec React. Pour cela, reprenons notre
exemple de gestion de listes d’éléments, dans lequel on peut insérer, modifier ou supprimer
des éléments de la liste.
React.js
280
On va donc créer le store de Redux dans le composant React le plus général de l’application
(souvent le composant <App>) et le transmettre aux autres composants via l’attribut store créé
dans les composants qui l’utiliseront. Les composants qui accéderont au store auront donc
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Si l’on ne procède pas à ces ajustements, on constatera un bogue lorsqu’un élément de liste sera sup-
primé et qu’on tentera de modifier l’élément suivant...
Fichier src/actions_types.js
React et Redux
281
CHAPITRE 10
Fichier src/actions.js
// Créateurs d’actions
export function add_elem(txt) {
var ukey = getUniqueKey(); // Attribuer une clé unique à l’élément créé
return {
type : ACTIONS.ADD_ELEM,
txt : txt,
ukey : ukey
}
}
La clé unique est attribuée lors de l’action de création de l’élément de liste (action ADD_ELEM).
L’action MODIFY_ELEM prend en paramètres la clé unique de l’élément à modifier et la nouvelle
valeur de cet élément.
67756-React.js-INT.book Page 282 Friday, March 1, 2019 7:15 PM
React.js
282
Le reducer est modifié pour prendre en compte la gestion de la clé unique et l’ajout de
l’action MODIFY_ELEM.
Fichier src/reducers.js
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
const stateInit = {
elems : [], // Tableau { ukey, txt }
revert : false,
find : {
tag : "",
elems : []
}
}
React et Redux
283
CHAPITRE 10
Le reducer est modifié pour que le tableau elems soit maintenant un tableau d’objets { ukey,
txt } permettant ainsi d’associer à chaque élément une clé unique, laquelle permettra de
modifier ou supprimer l’élément.
Une fois ces ajouts et modifications effectués, créons les composants nécessaires pour notre
application React reliée à Redux. On va traiter les cas suivants :
• ajout d’un élément dans la liste ;
• suppression d’un élément dans la liste ;
• modification d’un élément dans la liste ;
• inversion de la liste à l’affichage.
Mais avant cela, voyons comment s’organise globalement l’application du côté React.
Fichier src/index.js
ReactDOM.render(
<App />,
document.getElementById("root"));
React.js
284
éléments. Cette liste comporte par défaut cinq éléments ("Element1", "Element2", …,
"Element5").
Le composant <App> crée le store Redux et le transmet à ses composants fils.
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
<div>
<ButtonAdd text="Ajouter" store={store}></ButtonAdd>
<ConnectedListeElements elems={elems} store={store} />
</div>
)
}
}
Le bouton Ajouter est créé sous forme de composant <ButtonAdd>, et la liste d’éléments est
affichée avec le composant <ConnectedListeElements> (voir ci-après).
La propriété store est transmise à tous les composants qui en auront besoin (qui la transmet-
tront également à leurs composants fils).
Expliquons maintenant le composant <ConnectedListeELements>. Il utilise en attributs la
liste initiale elems des éléments à afficher et le store Redux. Au chapitre 6, on avait utilisé
uniquement le composant <ListeELements> qui affichait la liste d’éléments. N’oublions pas
que la liste d’éléments est désormais gérée avec le store de Redux. Il faut donc que la liste des
67756-React.js-INT.book Page 285 Friday, March 1, 2019 7:15 PM
React et Redux
285
CHAPITRE 10
éléments soit rafraîchie si besoin lors de chaque action sur la liste (ajout, suppression, modifi-
cation, inversion). Le composant <ConnectedListeElements> va servir à prendre en compte
les actions de Redux et rafraîchir la liste, tandis que le composant <ListeElements> servira
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
React.js
286
Le composant <Element> est également un simple composant d’affichage décrit par une
fonction.
Enfin, le bouton Ajouter (un élément dans la liste) est décrit par le composant <ButtonAdd>,
également sous forme de fonction.
67756-React.js-INT.book Page 287 Friday, March 1, 2019 7:15 PM
React et Redux
287
CHAPITRE 10
Vérifions le bon fonctionnement de ces composants avec Redux. On souhaite afficher une
liste d’éléments par défaut et un bouton Ajouter, inactif pour l’instant.
Figure 10–1
La liste par défaut des cinq éléments est affichée, ainsi que le bouton Ajouter permettant
d’insérer un élément. Pour l’instant, le code écrit précédemment fonctionne (et la connexion
avec Redux est établie).
Le clic sur le bouton Ajouter ne fonctionne pas encore. Nous allons voir ci-après comment
traiter le clic sur ce bouton.
67756-React.js-INT.book Page 288 Friday, March 1, 2019 7:15 PM
React.js
288
store.dispatch(ACTIONS.add_elem(txt));
Cette instruction nous a déjà servi pour insérer des éléments d’initialisation dans la liste. C’est le
fait d’avoir effectué this.setState() dans le callback de store.subscribe(callback) (du
composant <ConnectedListeElements>) qui permet de rafraîchir l’affichage à chaque insertion.
Il faut donc que cette instruction d’ajout soit appelée à chaque clic sur le bouton Ajouter. Le
composant à modifier est <ButtonAdd>, il correspond au bouton Ajouter.
React et Redux
289
CHAPITRE 10
Figure 10–2
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
store.dispatch(ACTIONS.remove_elem(ukey));
Pour cela, on insère un bouton Supprimer en face de chaque élément de liste, qui permettra de
supprimer cet élément. Chaque bouton Supprimer est représenté par un composant
<ButtonRemove> dans lequel sera effectué le traitement de la suppression de l’élément.
Le composant <Element> est donc modifié pour intégrer le bouton Supprimer devant chaque
élément de liste.
67756-React.js-INT.book Page 290 Friday, March 1, 2019 7:15 PM
React.js
290
L’objet store est transmis au composant <ButtonRemove> afin que ce composant puisse
traiter la suppression de l’élément de liste.
La propriété ukey de l’élément de liste est également transmise au composant afin qu’il sache
quel élément supprimer (à partir de sa clé unique).
Le composant <ButtonRemove> est créé pour prendre en compte le clic sur le bouton Sup-
primer. Il s’écrit sous forme de simple fonction.
Le clic sur le bouton appelle la méthode handlerClick() définie en interne dans le compo-
sant. Cette méthode supprime l’élément de liste en utilisant l’action REMOVE_ELEM.
Il faut bien sûr importer le fichier des actions afin de pouvoir les utiliser dans le composant.
Remarquons qu’on peut également écrire les paramètres de la fonction sous la forme suivante.
Cela remplace l’objet props indiqué en paramètre.
67756-React.js-INT.book Page 291 Friday, March 1, 2019 7:15 PM
React et Redux
291
CHAPITRE 10
La liste des propriétés de l’objet props est directement indiquée dans un objet en paramètre
de la fonction, comme ES6 le permet.
Testons à présent si cela fonctionne. Après suppression de quelques éléments de la liste, on
obtient le résultat suivant (figure 10-3).
Figure 10–3
React.js
292
store.dispatch(ACTIONS.modify_elem(ukey, txt));
Pour permettre la modification d’un élément de la liste, on autorise le double-clic sur chaque
élément de liste, qui sera alors remplacé par un champ de saisie permettant la modification.
Lors de la sortie du champ, le texte associé à l’élément est alors modifié.
Commençons par permettre la transformation du texte en champ de saisie, par un double-
clic. L’affichage de la liste devra afficher soit des éléments statiques non modifiables, soit des
éléments modifiables si l’on a double-cliqué dedans. Pour réaliser cela, il faut que l’état de
chaque élément de liste indique si l’élément est en cours de modification ou non. On voit
donc que l’on doit introduire une nouvelle propriété dans l’état associé à chaque élément de
liste. On avait déjà effectué cela dans l’exemple étudié au chapitre 6 en introduisant la pro-
priété modifyOn dans l’état de chaque élément de liste (dans la classe Element).
Mais ici, l’état global de l’application est géré par Redux dans le store. On pourrait modifier
l’état de chaque élément inséré grâce à la propriété elems du store (en y introduisant un
attribut modifyOn), mais il est plus judicieux de gérer l’état de l’élément directement dans le
composant <Element> (avec this.state.modifyOn).
La propriété modifyOn de l’état est vraiment locale au composant <Element>, et il n’y a aucune
chance qu’un autre composant ait besoin d’y accéder. Si c’était le cas, il faudrait alors mettre
cette propriété dans le store de Redux pour permettre un accès aux autres composants.
Afin de gérer l’état interne dans le composant <Element>, on doit transformer ce composant
en classe Element (au lieu de la simple fonction Element précédente). En effet, this.state
n’est accessible que dans une classe dérivant de React.Component...
React et Redux
293
CHAPITRE 10
render() {
const { store, ukey, text } = this.props;
return (
<div>
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
{ this.state.modifyOn ?
<input autoFocus={true} value={text} /> :
<span onDoubleClick={this.handlerDoubleClick.bind(this)}>{text}</span>
}
<ButtonRemove style={{margin:"10px", fontSize:"10px"}}
ukey={ukey} text="Supprimer" store={store}/>
</div>
)
}
}
React.js
294
Le double-clic sur un élément de liste affiche un champ de saisie non modifiable, car comme
indiqué dans le message d’erreur de React affiché dans la console, il faut implémenter l’événe-
ment onChange...
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Implémentons l’événement onChange sur le champ de saisie (tel qu’on a appris à le faire au
chapitre 6), ainsi que l’événement onBlur sur ce champ pour traiter la modification du store
de Redux (action MODIFY_ELEM).
React et Redux
295
CHAPITRE 10
)
}
}
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
React.js
296
store.dispatch(ACTIONS.revert_list());
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Le bouton Inverser est inséré à côté du bouton Ajouter dans le composant <App>. Pour traiter
le bouton Inverser, on lui associe un composant <ButtonRevert>.
Le principe du bouton Inverser est le même que celui du bouton Ajouter. On importe le
fichier du composant <ButtonRevert> associé au bouton Inverser.
Le traitement du clic sur le bouton Inverser est effectué dans le composant <ButtonRevert>,
qui est une simple fonction.
67756-React.js-INT.book Page 297 Friday, March 1, 2019 7:15 PM
React et Redux
297
CHAPITRE 10
Lors du clic sur le bouton, l’action REVERT_LIST définie dans Redux est appelée.
Vérifions que la liste s’inverse suite à un clic sur le bouton Inverser (figure 10-6).
Figure 10–6
Chaque clic sur le bouton Inverser inverse la liste à l’affichage. Les autres fonctionnalités
(ajout, suppression et modification) sont bien sûr opérationnelles.
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
67756-React.js-INT.book Page 298 Friday, March 1, 2019 7:15 PM
67756-React.js-INT.book Page 299 Friday, March 1, 2019 7:15 PM
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
11
Utiliser le module react-redux
cd reactapp
npm install react-redux
67756-React.js-INT.book Page 300 Friday, March 1, 2019 7:15 PM
React.js
300
Figure 11–1
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
• Pour lire l’état : effectuer une correspondance entre les propriétés définies dans l’état et
celles que l’on souhaite récupérer dans le composant (dans l’objet props du composant).
On indiquera, pour chaque composant, les propriétés de l’état utilisées dans le composant
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
et le nom qui leur est associé dans le composant (souvent le même). Cette correspondance
est effectuée dans une fonction appelée mapStateToProps(state) qui retourne un objet
établissant la correspondance entre les noms des attributs de l’état de Redux et les noms
des propriétés utilisées dans le composant.
• Pour exécuter une action : effectuer une correspondance entre les actions définies dans
Redux et celles que l’on souhaite utiliser dans le composant (via l’objet props du compo-
sant). On indiquera, pour chaque composant, les actions Redux utilisées dans le compo-
sant et le nom qui leur est associé dans le composant (souvent le même). Cette correspon-
dance est effectuée dans une fonction appelée mapDispatchToProps(dispatch) qui
retourne un objet établissant la correspondance entre les noms des actions de Redux et les
noms des propriétés (en fait des méthodes) utilisées dans le composant.
Grâce aux correspondances établies, on voit que le store devient transparent dans les compo-
sants, et que chaque composant accède aux éléments de l’état et aux actions qu’il souhaite,
sans avoir à transmettre des informations (telles que le store) dans les attributs des compo-
sants. C’est la méthode connect() qui va le faire pour nous.
Ceci implique cependant d’écrire le reducer et les actions correspondantes. La seule facilité
apportée par le module "react-redux" (via la méthode connect() sous-jacente) est de mettre
facilement à disposition dans chaque composant, les attributs de l’état et les actions utilisées
dans ce composant. Mais c’est tout de même un apport énorme !
React.js
302
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>
, document.getElementById("root"));
Nous avions utilisé cet exemple dans le chapitre 4 pour illustrer la notion d’état. Nous l’utili-
sons ici pour montrer l’utilisation du module "react-redux" sur un exemple simple.
Pour cet exemple du timer, nous utilisons l’action DECR_TIME qui diminue le temps restant de
1 seconde. Le temps restant est mis dans l’état de Redux, sous forme d’une propriété time
valant { min, sec }, min et sec indiquant respectivement le nombre de minutes et de
secondes restantes avant d’arriver à 00:00.
// Créateurs d’actions
export function decr_time({min, sec}) {
return {
type : ACTIONS.DECR_TIME,
time : {min, sec}
}
}
var stateInit = {
time : { min : 2, sec : 0 } // Timer initialisé à 02:00
}
React.js
304
else {
sec = 59;
}
}
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Le fichier du reducer traite l’action DECR_TIME qui sera utilisée pour diminuer le temps restant
de 1 seconde à chaque appel de l’action.
Les fichiers précédents sont classiques dans le cadre de l’utilisation de Redux, avec ou sans le
module "react-redux". En revanche, le fichier index.js de démarrage de l’application sera
différent selon qu’on utilise le module "react-redux" ou non. Dans le cas où le module est
utilisé, le fichier index.js s’écrit :
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>
, document.getElementById("root"));
Il reste maintenant à décrire le fichier du composant <App> qui affiche le timer. On suppose
ici que l’on utilise le module "react-redux", donc voyons d’abord comment sont utilisées
entre autres les fonctions mapStateToProps() et mapDispatchToProps().
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Appel de la méthode connect() dans le cas où l’on n’utilise pas la lecture de l’état de Redux
dans le composant
React.js
306
constructor(props) {
super(props);
}
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
formatTime({min, sec}) {
// Formate l’heure sous la forme mm:ss
if (min < 10) min = "0" + min; // 9 => "09"
if (sec < 10) sec = "0" + sec; // 9 => "09"
return `${min}:${sec}`; // de la forme "10:08"
}
render() {
var time = this.formatTime(this.props.time);
return (
<div>{time}</div>
)
}
}
function mapStateToProps(state) {
return {
// La propriété time de l’état devient la propriété time du composant
time : state.time
}
}
Figure 11–2
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>
, document.getElementById("root"));
setInterval(function() {
var time = store.getState().time;
store.dispatch(ACTIONS.decr_time(time));
}, 1000);
67756-React.js-INT.book Page 308 Friday, March 1, 2019 7:15 PM
React.js
308
Une fois l’import du fichier actions.js réalisé, la méthode ACTIONS.decr_time() est acces-
sible. On l’utilise en lui indiquant la valeur time de l’état de Redux, qu’elle décrémente. Cette
mise à jour de l’état provoque le nouvel affichage du composant <App> car celui-ci est lié au
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
composant, sous forme de propriétés (ici des méthodes accessibles à travers l’objet props). Ces
actions permettent de mettre à jour l’état de Redux (alors que la fonction mapStateToProps()
vue précédemment permet de rendre l’état de Redux accessible en lecture seulement).
La fonction mapDispatchToProps() s’inscrit en deuxième paramètre de la méthode
connect(). Elle retourne un objet indiquant les nouvelles propriétés disponibles dans le com-
posant, liées aux actions de Redux. Par exemple, si l’action add_elem(txt) existe dans les
actions de Redux, il est possible pour un composant d’accéder à cette action en écrivant la
fonction mapDispatchToProps(dispatch) suivante.
function mapStateToProps(state) {
return {
// ...
}
}
function mapDispatchToProps(dispatch) {
return {
add_elem : function(txt) {
var action = ACTIONS.add_elem(txt);
dispatch(action);
}
}
}
La propriété add_elem est maintenant définie dans le composant, elle est donc accessible par
l’objet props disponible dans celui-ci.
Utilisons la fonction mapDispatchToProps() pour permettre au composant <App> définissant
le timer d’accéder à l’action DECR_TIME. Cela permet de positionner la fonction
setInterval() dans la classe App plutôt que de l’utiliser dans le fichier index.js (ce qui était
67756-React.js-INT.book Page 310 Friday, March 1, 2019 7:15 PM
React.js
310
alors obligatoire afin de pouvoir accéder à l’objet store de Redux qui n’était visible que dans
le fichier index.js où il était défini).
Le fichier index.js est simplifié car il n’utilise plus l’instruction setInterval(), qui est
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Fichier src/index.js
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>
, document.getElementById("root"));
componentDidMount() {
setInterval(() => {
var time = this.props.time; // Accessible grâce à mapStateToProps()
this.props.decr_time(time); // Accessible grâce à mapDispatchToProps()
}, 1000);
}
67756-React.js-INT.book Page 311 Friday, March 1, 2019 7:15 PM
formatTime({min, sec}) {
// Formate l’heure sous la forme mm:ss
if (min < 10) min = "0" + min; // 9 => "09"
if (sec < 10) sec = "0" + sec; // 9 => "09"
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
render() {
var time = this.formatTime(this.props.time);
return (
<div>{time}</div>
)
}
}
function mapStateToProps(state) {
return {
time : state.time
}
}
function mapDispatchToProps(dispatch) {
return {
decr_time : function({ min, sec }) {
var action = ACTIONS.decr_time({ min, sec });
dispatch(action);
}
}
}
React.js
312
Figure 11–4
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Les noms des fichiers et des composants sont les mêmes que ceux définis dans le chapitre
précédent, à l’exception du composant <ConnectedListeElements> qui n’a plus besoin
d’exister ici, car il est avantageusement remplacé par les fonctionnalités apportées par le
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Fichier src/index.js
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>
, document.getElementById("root"));
React.js
314
// Créateurs d’actions
export function add_elem(txt) {
var ukey = getUniqueKey(); // Attribuer une clé unique à l’élément créé
return {
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
type : ACTIONS.ADD_ELEM,
txt : txt,
ukey : ukey
}
}
const stateInit = {
elems : [], // Tableau { ukey, txt }
revert : false,
find : {
tag : "",
elems : []
}
}
67756-React.js-INT.book Page 315 Friday, March 1, 2019 7:15 PM
React.js
316
C’est le même fichier que précédemment, sauf pour les parties mises en évidence dans le
code. En effet, on a constaté que les instructions elems.reverse(); et elems.push({txt,
ukey}); ne provoquaient pas de modification de l’état, d’où l’ajout à leur suite de l’instruction
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
elems.map() qui ne fait que retourner le même tableau que celui reçu, mais provoque en
revanche une modification de l’état de Redux...
Les fichiers précédents ne concernent pas les composants React, c’est pour cela que les modi-
fications sont minimes par rapport à la version précédente. Les modifications véritables vont
maintenant intervenir lors de l’écriture des composants.
function mapDispatchToProps(dispatch) {
return {
add_elem : function(txt) {
var action = ACTIONS.add_elem(txt);
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
dispatch(action);
}
}
}
L’insertion des premiers éléments de liste s’effectue par l’action ADD_ELEM. Cette action est
donc mise dans les propriétés du composant (ici, <App>) afin qu’il puisse utiliser la méthode
via this.props.add_elem().
function mapStateToProps(state) {
return {
elems : state.elems
}
}
La liste des éléments (elems) est inscrite dans l’état de Redux, donc on permet un accès en
lecture à cette partie de l’état via la fonction mapStateToProps().
67756-React.js-INT.book Page 318 Friday, March 1, 2019 7:15 PM
React.js
318
function mapDispatchToProps(dispatch) {
return {
modify_elem : function(ukey, value) {
var action = ACTIONS.modify_elem(ukey, value);
dispatch(action);
}
67756-React.js-INT.book Page 319 Friday, March 1, 2019 7:15 PM
}
}
L’action MODIFY_ELEM est utilisée lors de la modification d’un élément de liste, elle est donc
mise en propriété du composant <Element>.
function mapStateToProps(state) {
return {
elems : state.elems
}
}
function mapDispatchToProps(dispatch) {
return {
add_elem : function(txt) {
var action = ACTIONS.add_elem(txt);
dispatch(action);
}
}
}
React.js
320
function mapDispatchToProps(dispatch) {
return {
remove_elem : function(ukey) {
var action = ACTIONS.remove_elem(ukey);
dispatch(action);
}
}
}
function mapDispatchToProps(dispatch) {
return {
revert_list : function() {
var action = ACTIONS.revert_list();
dispatch(action);
}
}
}
Figure 11–5
Conclusion
Nous terminons ici l’utilisation de Redux dans le cadre d’un projet React. Redux simplifie
grandement l’accès à l’état dans les composants React, en particulier si des parties de l’état
doivent être partagées dans divers composants.
Le module "react-redux" apporte également une couche de simplification en évitant de
propager l’attribut store dans les composants React. On utilise ces deux modules ("redux" et
"react-redux") dans le cadre de projets importants qui nécessitent de partager de nom-
breuses données entre les composants. Ces modules sont devenus indispensables dans les pro-
jets utilisant React.
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
67756-React.js-INT.book Page 322 Friday, March 1, 2019 7:15 PM
67756-React.js-INT.book Page 323 Friday, March 1, 2019 7:15 PM
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
12
React Router
React Router est un ensemble de modules permettant d’utiliser des routes dans une applica-
tion React. Une route représente une URL dans le navigateur et correspond à un affichage
dans la fenêtre, c’est-à-dire à l’affichage de un ou plusieurs composants React.
L’intérêt des routes est de pouvoir facilement gérer quels composants on souhaite afficher, en
fonction de l’URL indiquée. Si l’URL change, les composants affichés ne sont plus les
mêmes, et on a donc l’impression d’avoir changé de page HTML, ce qui n’est pas le cas.
De plus, un mécanisme d’historique des URL visitées est implémenté dans React Router, per-
mettant ainsi de pouvoir revenir en arrière dans l’historique à l’aide de la touche Précédent du
navigateur. Sans ce mécanisme, le retour en arrière produit la sortie de l’application React, car
celle-ci est dans une seule page index.html, selon le principe SPA (Single Page Application).
React Router existe en version web (utilisée ici) et en version pour application native (non
utilisée ici). Nous installerons donc la version web dans le répertoire reactapp de l’application
créée dans les chapitres précédents (figure 12-1).
cd reactapp
npm install react-router-dom
Une fois les modules associés à React Router installés, l’application React qui les utilise (ici, le
composant <App>) doit être insérée dans le composant <BrowserRouter> défini dans React
Router. Le fichier index.js est modifié de la façon suivante :
67756-React.js-INT.book Page 324 Friday, March 1, 2019 7:15 PM
React.js
324
Figure 12–1
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>
, document.getElementById("root"));
Le composant <BrowserRouter> est un composant défini dans React Router et inclus grâce à
l’instruction import présentée dans ce code.
Le composant <App> de l’application est directement inséré dans le composant
<BrowserRouter>.
Notez que le composant <BrowserRouter> ne peut posséder qu’un seul enfant direct, d’où
l’intérêt de regrouper toute l’application dans le composant <App>.
Une fois le composant <BrowserRouter> positionné, le composant <App> (et ses composants
internes) peut utiliser les routes qui seront définies.
67756-React.js-INT.book Page 325 Friday, March 1, 2019 7:15 PM
React Router
325
CHAPITRE 12
React Router).
Pour commencer, définissons deux routes dans le composant <App> :
• la route "/" affiche "Route /" ;
• la route "/app" affiche "Route /app".
Cela signifie que :
• Si l’URL dans le navigateur est http://localhost:3000, on affiche "Route /".
• Si l’URL dans le navigateur est http://localhost:3000/app, on affiche "Route /app".
Le fichier du composant <App> est modifié pour prendre en compte ces deux routes au moyen
de deux composants <Route>.
function App(props) {
return (
<div>
<Route path="/" render={()=><div>Route /</div>} />
<Route path="/app" render={()=><div>Route /app</div>} />
</div>
)
}
Le composant <Route> utilise ici les deux attributs path et render. L’attribut path indique la
route qui déclenche l’affichage associé à cette route (décrit dans l’attribut render), tandis que
l’attribut render indique une fonction de callback qui retourne les éléments React à afficher
(lorsque cette route est affichée). D’autres attributs du composant <Route> sont disponibles et
étudiés ci-après.
La fonction de callback indiquée dans l’attribut render est ici écrite en ES6, mais il est égale-
ment possible de l’écrire de façon moins concise, comme ceci :
React.js
326
Figure 12–2
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Le render associé à la route "/" s’affiche, et nous voyons dans l’onglet React les deux compo-
sants <Route> dont seul le premier contient le <div> affiché (le second composant <Route> a
maintenant un contenu vide).
C’est le composant <BrowserRouter> qui, en fonction de la route indiquée dans l’URL,
affiche le contenu du composant <Route> correspondant à la route.
Utilisons maintenant l’URL http://localhost:3000/app dans le navigateur (figure 12-3).
À notre grande surprise, les affichages des deux routes se produisent, bien que la route indi-
quée dans l’URL soit "/app"...
La raison de l’affichage simultané des deux routes est simple : l’attribut path indiqué dans le
composant <Route> signifie que l’URL doit comporter cette chaîne de caractères, mais cela
ne signifie pas que ce soit exactement cette valeur.
Donc quand on indique "/app" dans l’URL, la première route avec path="/" convient car le
path indiqué est dans l’URL, et la seconde route avec path="/app" convient également pour
la même raison. Ainsi, toutes les routes qui conviennent affichent leur render, ce qui est bien
le cas ici.
On voit donc que lors de l’utilisation de <Route>, toutes les routes dont l’attribut path corres-
pond avec l’URL vont s’afficher. Pour permettre de n’afficher qu’une seule route parmi celles
qui pourraient correspondre (en fait, la première qui correspond), il faut utiliser en plus le
composant <Switch>.
67756-React.js-INT.book Page 327 Friday, March 1, 2019 7:15 PM
React Router
327
CHAPITRE 12
Figure 12–3
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
function App(props) {
return (
67756-React.js-INT.book Page 328 Friday, March 1, 2019 7:15 PM
React.js
328
<Switch>
<Route path="/" render={()=><div>Route /</div>} />
<Route path="/app" render={()=><div>Route /app</div>} />
</Switch>
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
)
}
Le composant <Switch> est importé de la même façon que le composant <Route>. Il entoure
les deux composants <Route> précédents.
Affichons de nouveau l’URL http://localhost:3000/app (figure 12-4).
Figure 12–4
Une seule route est maintenant affichée (la première dont le path correspond à l’URL).
De plus, le composant <Switch> a supprimé le deuxième composant <Route>.
Il reste toutefois un autre problème. En effet, il n’est pas normal que lorsque l’on indique
"/app" dans l’URL, ce soit la route ayant path="/" qui soit sélectionnée (même si ce compor-
tement est normal dans React Router). Il serait plus logique que la route ayant path="/app"
soit choisie en premier si l’URL contient "/app". C’est le rôle de l’attribut exact dans le com-
posant <Route>.
67756-React.js-INT.book Page 329 Friday, March 1, 2019 7:15 PM
React Router
329
CHAPITRE 12
function App(props) {
return (
<Switch>
<Route exact={true} path="/" render={()=><div>Route /</div>} />
<Route path="/app" render={()=><div>Route /app</div>} />
</Switch>
)
}
L’attribut exact est positionné à une valeur booléenne true ou false. On considère en JSX
que si l’attribut est présent, il vaut true si la valeur n’est pas indiquée (la présence de l’attribut
suffit). Et si l’attribut n’est pas présent, sa valeur est false par défaut.
Par conséquent, on aurait également pu écrire :
Figure 12–6
Figure 12–5
React.js
67756-React.js-INT.book Page 330 Friday, March 1, 2019 7:15 PM
67756-React.js-INT.book Page 331 Friday, March 1, 2019 7:15 PM
React Router
331
CHAPITRE 12
Par exemple, si l’on indique l’URL http://localhost:3000/abc, la valeur "/abc" n’étant indiquée
dans aucun path des composants <Route>.
Utilisons l’URL http://localhost:3000/abc (figure 12-7).
Figure 12–7
Lorsque l’URL indiquée n’est reconnue par aucune route, rien ne s’affiche et les composants
<Route> ont été supprimés de l’application par React Router.
L’erreur d’URL étant une erreur fréquente, il serait bon d’afficher un message d’erreur aux
utilisateurs.
Pour cela, il suffit d’indiquer une route n’ayant pas l’attribut path indiqué (ou l’attribut
path="") en dernier dans la liste des routes. En effet, si aucune des routes précédentes n’est
choisie, la dernière, qui n’a pas le path indiqué, sera forcément choisie par React Router car
elle ne peut que convenir.
67756-React.js-INT.book Page 332 Friday, March 1, 2019 7:15 PM
React.js
332
function App(props) {
return (
<Switch>
<Route exact={true} path="/" render={()=><div>Route /</div>} />
<Route path="/app" render={()=><div>Route /app</div>} />
<Route render={()=><div>Route inconnue</div>} />
</Switch>
)
}
La route sans path est indiquée en dernier (car si elle était indiquée avant, elle conviendrait à
coup sûr et empêcherait les routes qui suivent d’être prises en considération).
Utilisons encore une URL avec une route inconnue, par exemple http://localhost:3000/abc
(figure 12-8).
Figure 12–8
67756-React.js-INT.book Page 333 Friday, March 1, 2019 7:15 PM
React Router
333
CHAPITRE 12
L’attribut render utilisé dans le composant <Route> peut servir à afficher des éléments React
quelconques, y compris ceux que nous avons nous-mêmes créés (composants créés sous forme
de fonctions ou de classes).
Utilisons la route "/" pour afficher une liste d’éléments ("Element1", …, "Element5"). On
utilise pour cela le composant <ListeElements> auquel on transmet dans l’attribut elems le
tableau d’éléments à afficher.
function App(props) {
var elems = [
"Element1",
"Element2",
"Element3",
"Element4",
"Element5"
];
return (
<Switch>
<Route exact={true} path="/"
render={()=><ListeElements elems={elems} />} />
<Route render={()=><div>Route inconnue</div>} />
</Switch>
)
}
On transmet dans le composant <ListeElements> l’attribut elems comportant la liste des élé-
ments à afficher.
Le composant <ListeElements> affiche le tableau elems transmis dans son objet props.
67756-React.js-INT.book Page 334 Friday, March 1, 2019 7:15 PM
React.js
334
Le composant <Element>, quant à lui, affiche la valeur indiquée dans l’attribut elem qui lui
est transmis.
React Router
335
CHAPITRE 12
Figure 12–9
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Remarque
Remarquez que pour utiliser des variables dans la définition des routes, on préfixe le nom de la variable (ici,
index) avec ":", d’où ici ":index". C’est une règle de React Router.
67756-React.js-INT.book Page 336 Friday, March 1, 2019 7:15 PM
React.js
336
La deuxième route nécessite de pouvoir transférer l’index de l’élément indiqué dans l’URL
vers le composant affiché par render. Si l’on utilise encore le composant <ListeElements>
pour afficher cette route, il faudra que ce composant utilise également l’index de l’élément si
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
cet index est transmis (si l’index n’est pas transmis, la liste est affichée dans sa globalité
comme dans la première route).
La question qui se pose alors est comment transférer une valeur inscrite dans la route (donc
en fait l’URL) vers le composant utilisé par l’attribut render de cette route ? En fait, le com-
posant récupère dans son objet props (ou this.props si le composant est décrit par une
classe) des éléments qui sont ajoutés par React Router.
Pour le vérifier, il suffit de créer la route "/edit/:index" dans nos routes, et d’afficher pour
celle-ci le contenu de l’objet props reçu lors du render.
function App(props) {
var elems = [
"Element1",
"Element2",
"Element3",
"Element4",
"Element5"
];
return (
<Switch>
<Route exact={true} path="/"
render={()=><ListeElements elems={elems} />} />
<Route path="/edit/:index"
render={(props)=><div>{JSON.stringify(props)}</div>} />
<Route render={()=><div>Route inconnue</div>} />
</Switch>
)
}
React Router
337
CHAPITRE 12
Figure 12–10
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
La propriété match contient un objet params contenant les paramètres indiqués dans l’URL,
ici { index : "2" }. Par conséquent, pour accéder à la valeur de l’index, il suffit d’écrire
l’expression props.match.params.index.
Écrivons le fichier du composant <App> en utilisant l’objet props transmis dans l’attribut
render.
function App(props) {
var elems = [
"Element1",
"Element2",
"Element3",
"Element4",
67756-React.js-INT.book Page 338 Friday, March 1, 2019 7:15 PM
React.js
338
"Element5"
];
return (
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
<Switch>
<Route exact={true} path="/"
render={(props)=><ListeElements {...props} elems={elems} />} />
<Route path="/edit/:index"
render={(props)=><ListeElements {...props} elems={elems} />} />
<Route render={()=><div>Route inconnue</div>} />
</Switch>
)
}
L’objet props est transmis dans les attributs du composant <ListeElements>, de façon à ce
que ce composant puisse connaître la route qui provoque son affichage. Afin de concaténer
cet objet avec l’attribut elems déjà utilisé, on utilise la syntaxe ES6 avec { ...props } dans
les deux routes.
Le composant <ListeElements> utilisé pour afficher la liste des éléments ou un seul élément
(selon la route utilisée) s’écrit maintenant ainsi.
Composant <ListeElements> affichant une liste ou un seul élément (selon la route utilisée)
Si l’URL contient "/edit", on affiche un seul élément (en utilisant la valeur de l’index trans-
mise dans l’URL), sinon on affiche la liste complète comme précédemment.
67756-React.js-INT.book Page 339 Friday, March 1, 2019 7:15 PM
React Router
339
CHAPITRE 12
React.js
340
Figure 12–12
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
React Router
341
CHAPITRE 12
function App(props) {
var elems = [
"Element1",
"Element2",
"Element3",
"Element4",
"Element5"
];
return (
<div>
<a href="/">Liste complete</a>
<a href="/edit/2">Index 2</a>
<Switch>
<Route exact={true} path="/"
render={(props)=><ListeElements {...props} elems={elems} />} />
<Route path="/edit/:index"
render={(props)=><ListeElements {...props} elems={elems} />} />
<Route render={()=><div>Route inconnue</div>} />
</Switch>
</div>
)
}
Les liens sont ici de simples éléments <a> dont l’attribut href représente la route.
Démarrons le programme en introduisant l’URL http://localhost:3000 (figure 12-13).
La liste complète s’affiche, ainsi que les deux liens.
Cliquons sur le second lien pour afficher un seul élément de liste (figure 12-14).
Suite au clic sur le lien, l’élément d’index 2 s’affiche dans la page.
Le fonctionnement du programme semble normal. Cependant, en observant bien, on s’aper-
çoit qu’à chaque clic sur l’un des liens, la page complète se réaffiche. En fait, le clic sur un des
liens recharge la page en totalité dans le navigateur, sans tenir compte du fait qu’elle est déjà
présente.
Ce n’est pas du tout le comportement que l’on souhaite avoir en utilisant React Router... Pour
remédier à ce problème, React Router fournit un nouveau composant appelé <Link> qui
permet de remplacer l’élément <a> dans les pages, et de ne pas recharger la page étant donné
que celle-ci est déjà présente.
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
342
Figure 12–14
Figure 12–13
React.js
67756-React.js-INT.book Page 342 Friday, March 1, 2019 7:15 PM
67756-React.js-INT.book Page 343 Friday, March 1, 2019 7:15 PM
React Router
343
CHAPITRE 12
L’utilisation du composant <Link> est similaire à celle de l’élément <a>. L’attribut href est
simplement remplacé par l’attribut to.
function App(props) {
var elems = [
"Element1",
"Element2",
"Element3",
"Element4",
"Element5"
];
return (
<div>
<Link to="/">Liste complete</Link>
<Link to="/edit/2">Index 2</Link>
<Switch>
<Route exact={true} path="/"
render={(props)=><ListeElements {...props} elems={elems} />} />
<Route path="/edit/:index"
render={(props)=><ListeElements {...props} elems={elems} />} />
<Route render={()=><div>Route inconnue</div>} />
</Switch>
</div>
)
}
Le composant <Link> est importé comme les autres composants de React Router.
Les liens <a> ont été remplacés par les composants <Link>.
L’affichage est similaire à celui utilisant les liens <a>. Mais lors d’un clic sur un lien, la page ne
se recharge pas et la fluidité est maximale.
Remarquez également, suite aux clics sur les liens, que le bouton Précédent du navigateur
permet de naviguer entre les différentes URL visitées, ce qui n’était pas possible en dehors de
React Router.
67756-React.js-INT.book Page 344 Friday, March 1, 2019 7:15 PM
React.js
344
Il nous reste une dernière facette de React Router à vous présenter. Dans la précédente section,
on a montré comment afficher des liens pour naviguer dans les routes préalablement définies,
en utilisant le composant <Link> qui permet de conserver la même page en mémoire.
Mais que se passerait-il si l’on utilisait des boutons au lieu des liens ? Un bouton ne possède
pas d’attributs href (comme l’élément <a>) ou to (comme le composant <Link>). La question
est donc : « Comment permettre d’accéder à une route de façon dynamique (par exemple, lors
d’un clic sur un bouton) ? »
Il faut dans ce cas utiliser un composant de React Router qui permet ce genre de manipula-
tion. Il s’agit du composant <Router>, à utiliser à la place du composant <BrowserRouter>. Il
offre plus de paramétrages que le composant <BrowserRouter>, et permet notamment de
manipuler l’historique de navigation.
Ainsi, pour afficher une route quelconque, il suffit de l’insérer dans le tableau des pages visi-
tées nommé history :
• pour afficher la route "/", on indique : history.push("/");
• pour afficher la route "/edit/2", on indique : history.push("/edit/2");
Voyons maintenant comment accéder au tableau history à partir du nouveau composant
<Router>.
ReactDOM.render(
<Router history={customHistory}>
<App history={customHistory} />
</Router>
, document.getElementById("root"));
React Router
345
CHAPITRE 12
Remarquez que lorsque l’on utilise directement le composant <BrowserRouter>, toutes ces
manipulations sont cachées à l’intérieur de ce composant...
Cet historique de navigation est également transmis au composant <App> de notre application
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
qui va l’utiliser pour afficher les nouvelles pages visitées suite aux clics sur les boutons.
Le composant <App> est modifié pour afficher les deux boutons au lieu des deux liens, et pour
gérer les clics sur ces boutons.
function App(props) {
var elems = [
"Element1",
"Element2",
"Element3",
"Element4",
"Element5"
];
function handlerClickFullList() {
props.history.push("/"); // Insertion de la route "/"
}
function handlerClickIndex2() {
props.history.push("/edit/2"); // Insertion de la route "/edit/2"
}
return (
<div>
<button onClick={handlerClickFullList}>Liste complete</button>
<button onClick={handlerClickIndex2}>Index 2</button>
<Switch>
<Route exact={true} path="/"
render={(props)=><ListeElements {...props} elems={elems} />} />
<Route path="/edit/:index"
render={(props)=><ListeElements {...props} elems={elems} />} />
<Route render={()=><div>Route inconnue</div>} />
</Switch>
</div>
)
}
React.js
346
Le clic sur chaque bouton est traité par une fonction, qui utilise l’objet history transmis dans
les attributs du composant <App> (figure 12-15).
Figure 12–15
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
Index
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34
A D
actions 262 defaultValue 191
addEventListener 160 dispatch 262
Ajax 230 done 232
assign 269
autoFocus 174 E
eslint 256
B event 152
Babel 72 exact 329
bind 126 export 42
BrowserRouter 323 extends 33
C F
charCode 156 fail 233
checked 197, 214 fetch 233
classes filter 148
objets 30 fonctions 11, 14
className 56, 77 forEach 212
Component 66 Fragment 93
componentDidMount 107
componentDidUpdate 108 G
componentWillMount 107 getState 262
componentWillReceiveProps 108, 113, 166, 204
componentWillUnmount 108 H
connect 300 héritage
const 4 classe 33
constructor 107 history 336
createBrowserHistory 344
createElement 52
I
create-react-app 237 import 45, 244
createStore 260 J
création dans un élément
enfants 58 JSX 71
key 61 L
map 60
let 5
React.Component 66
Link 341
location 336
67756-React.js-INT.book Page 348 Friday, March 1, 2019 7:15 PM
React.js
348
M R
mapDispatchToProps 309 radio 193
mapStateToProps 305 React 49
match 336 React Router 323
Ce document est la propriété exclusive de Louis CORREA (louis.correa@wanadoo.fr) - samedi 07 août 2021 à 19h34