├── README.md └── manuscript ├── Book.txt ├── chapter1.md ├── chapter2.md ├── chapter3.md ├── chapter4.md ├── chapter5.md ├── chapter6.md ├── contributor.md ├── deployChapter.md ├── finalwords.md └── foreword.md /README.md: -------------------------------------------------------------------------------- 1 | # The Road to learn React [Livre] 2 | 3 | [![Slack](https://slack-the-road-to-learn-react.wieruch.com/badge.svg)](https://slack-the-road-to-learn-react.wieruch.com/) 4 | 5 | Le dépôt officiel pour le livre open source [The Road to learn React](https://www.robinwieruch.de/the-road-to-learn-react/). De plus, ici vous pouvez aussi trouver le [code source](https://github.com/rwieruch/hackernews-client) et [le cours complet](https://roadtoreact.com/). Si vous voulez laisser un avis, vous pouvez le faire sur [Amazon](https://www.amazon.com/dp/B077HJFCQX?tag=21moves-20) ou [Goodreads](https://www.goodreads.com/book/show/37503118-the-road-to-learn-react). Ce livre est également hebergé sur [Leanpub](https://leanpub.com/the-road-to-learn-react-french). 6 | 7 | ## Mise à jour, aide et support 8 | 9 | * Obtenez les mises à jour du livre via [e-mail](https://www.getrevue.co/profile/rwieruch) ou [Twitter](https://twitter.com/rwieruch) 10 | * Obtenez de l'aide, lors de votre apprentissage de React sur le livre ou apprenez aux autres, grâce à la [chaîne Slack officielle](https://slack-the-road-to-learn-react.wieruch.com/) 11 | * Découvrez comment vous pouvez [supporter le livre](https://www.robinwieruch.de/about/) 12 | 13 | ## Contribuez 14 | 15 | Vous pouvez aider à l'amélioration du livre en ouvrant des Pull Requests (PR) et des Issues. 16 | 17 | Vous pouvez ouvrir n'importe quelle PR qui corrige l'orthographe ou explique une certaine leçon avec plus de détails. Lors de l'écriture d'un tel livre technique, vous serez rapidement attiré sur ceux qui a besoin de plus d'explication et sur ce qui est déjà bien expliqué. 18 | 19 | De plus, vous pouvez ouvrir des Issues lorsque vous rencontrez des problèmes. Dans le but de réparer l'Issue aussi facilement que possible, veuillez s'il vous plaît fournir un maximum de détails tel que les erreurs de log, un screenshot, quelle page du livre est concernée, votre version de node (commande : `node -v`) et un lien vers votre propre dépôt. Pas tous ces détails sont obligatoires, mais la plupart d'entre eux aident à réparer l'Issue et à améliorer le livre. 20 | 21 | Merci beaucoup de votre aide! 22 | 23 | ## Devenir un Patron 24 | 25 | The Road to learn React est un ebook gratuit qui doit permettre à tout le monde d'en apprendre au sujet de React. Ce type de contenu éducatif a besoin de votre soutient pour se maintenir de lui-même. Robin Wieruch écrit beaucoup de contenu éducatif sur [son site web](https://www.robinwieruch.de/). Donc vous pouvez le supporter en étant son [patron sur Patreon](https://www.patreon.com/rwieruch). 26 | -------------------------------------------------------------------------------- /manuscript/Book.txt: -------------------------------------------------------------------------------- 1 | {frontmatter} 2 | 3 | foreword.md 4 | contributor.md 5 | 6 | {mainmatter} 7 | 8 | chapter1.md 9 | chapter2.md 10 | chapter3.md 11 | chapter4.md 12 | chapter5.md 13 | chapter6.md 14 | deployChapter.md 15 | 16 | {backmatter} 17 | 18 | finalwords.md -------------------------------------------------------------------------------- /manuscript/chapter1.md: -------------------------------------------------------------------------------- 1 | # Introduction à React 2 | 3 | Ce chapitre fournit une introduction à React. Peut-être vous demander vous: Pourquoi devrais-je apprendre React? L'objectif de ce chapitre est de répondre à cette interrogation. Après quoi, nous plongerons à l'intérieur de l'écosystème en débutant par votre première application React à partir de rien nécessitant zéro configuration. Durant cette phase, vous serez introduit à JSX ainsi qu'au ReactDOM. Soyez prêt pour vos premiers composants React. 4 | 5 | ## Salut, mon nom est React. 6 | 7 | **Pourquoi devrez-vous, vous embêter à apprendre React** 8 | Ces dernières années les applications web monopage ([SPA](https://en.wikipedia.org/wiki/Single-page_application)) sont devenu populaires. Les frameworks comme Angular, Ember et Backbone aident les développeurs JavaScript à construire des applications web modernes au-delà du simple usage de Vanilla JavaScript et JQuery. La liste de ces solutions populaires n'est pas exhaustive. Il existe un large panel de frameworks pour SPA. Quand on compare les dates de sorties officielles, la plupart d'entre eux font partie de la première génération de SPAs: Angular 2010, Backbone 2010, Ember 2011. 9 | 10 | La sortie officielle de React par Facebook date de 2013. React n'est pas un framework SPA à proprement parler mais une bibliothèque gérant que la vue. C'est le "V" du fameux [MVC](https://en.wikipedia.org/wiki/Model–view–controller) (Model View Controller). Il permet seulement de rendre des composants en tant qu'élément visionnable dans le navigateur. Naturellement, l'écosystème autour de React rend possible la création de SPAs. 11 | 12 | Mais pourquoi vous devrez utiliser React plutôt que la première génération de frameworks SPA? Tandis que la première génération de frameworks essayèrent de résoudre beaucoup de problématiques à la fois, React vous assiste seulement pour construire votre couche: vue. C'est une bibliothèque et non un framework. L'idée derrière cela : votre vue est une hiérarchie de composants composables. 13 | 14 | Dans React vous pouvez conserver votre attention sur la couche : vue avant d'introduire plus de concepts pour votre application. Tous les autres concepts sont d'autres *building block* pour votre SPA. Ces *building blocks* sont essentiels pour construire une application mûre. Ils arrivent avec deux avantages. 15 | 16 | Tout d'abord, vous pouvez apprendre les constructions de blocs étape par étape. Vous n'avez pas à vous inquiéter à propos de l'agencement de tout cela. Ceci est différent d'un framework qui vous fournit des blocs préconstruits dès le début. Ce livre se concentre sur React pour construire en tant que premier bloc de construction. Plus de blocs de construction suivront finalement. 17 | Tout d'abord, vous pouvez apprendre les *building block* étape par étape. Vous n'avez pas à vous inquiéter à propos de l'agencement de tout cela. Ceci est différent d'un framework qui vous fournit des *building block* dès le début. Ce livre se concentre sur React en tant que premier *building block*. Plus de *building block* suivront finalement. 18 | 19 | Dans un second temps, tout *building blocks* sont interchangeable. Cela rend l'écosystème autour de React innovant. Plusieurs solutions s'affrontent entre eux. Vous pouvez dès lors récupérer la solution la plus attrayante pour vous et votre cas d'utilisation. 20 | 21 | La première génération de frameworks SPA arrivèrent à un déploiement en entreprise. Ils sont plus rigides. Tandis que React demeure innovant et tand à être adopté par plusieurs têtes pensantes d'entreprise leader tel que [Airbnb, Netflix et bien sûr Facebook](https://github.com/facebook/react/wiki/Sites-Using-React). Tous investissent dans le futur de React et satisfait et de react et de son écosystème. 22 | 23 | De nos jours, React est probablement l'un des meilleurs choix pour construire das applications web modernes. Il délivre seulement la couche vue, [mais l'écosystème React fournit un framework entièrement souple et interchangeable](https://www.robinwieruch.de/essential-react-libraries-framework/). React dispose d'une API épuré, d'un incroyable écosystème et d'une grande communauté. Vous pouvez lire à propos de mes expériences [pourquoi je suis passé d'Angular à React](https://www.robinwieruch.de/reasons-why-i-moved-from-angular-to-react/). Je recommande d'avoir une compréhension de pourquoi vous souhaitez choisir React plutôt qu'un autre framework ou bibliothèque. Après tout, tout le monde est enjoué à l'idée d'expérimenter vers où React nous conduira dans les prochaines années. 24 | 25 | ### Exercices 26 | 27 | * lire plus à propos [pourquoi je suis passé d'Angular à React](https://www.robinwieruch.de/reasons-why-i-moved-from-angular-to-react/) 28 | * lire plus à propos [l'écosystème souple de React](https://www.robinwieruch.de/essential-react-libraries-framework/) 29 | * lire plus à propos de [comment apprende un framework](https://www.robinwieruch.de/how-to-learn-framework/) 30 | 31 | ## Prérequis 32 | 33 | Quels sont les prérequis pour lire ce livre? Tout d'abord, si vous êtes déjà familier avec les bases du web développement. Vous devriez être familier quant à l'utilisation d'HTML, CSS et JavaScript. Peut-être, le terme [API](https://www.robinwieruch.de/what-is-an-api-javascript/) ne vous est pas étranger également, car nous allons utiliser des APIs dans ce livre. De plus, je vous encourage à rejoindre le [Groupe Slack] officiel (https://slack-the-road-to-learn-react.wieruch.com/) du livre pour être aidé ou aider les autres. 34 | 35 | ### Éditeur et terminal 36 | 37 | Qu'en est-il de l'environnement de développement? Vous aurez besoin d'un éditeur ou d'un IDE et d'un terminal (*command line tool*). Vous pouvez [suivre mon guide d'installation](https://www.robinwieruch.de/developer-setup/). C'est illustré pour les utilisateurs de MacOS, mais vous pouvez trouver un guide d'installation Windows pour React également. En général, il y a une pléthore d'articles qui vous montreront comment installer un environnement de développement pour le web et de façon plus élaborée pour votre OS. 38 | 39 | Optionnellement, vous pouvez utiliser Git et Github par vous-même, pendant la réalisation des exercices du livre, pour conserver vos projets et la progression dans les dépôts de Github. Il existe un [petit guide](https://www.robinwieruch.de/git-essential-commands/) sur comment utiliser ces outils. Mais encore une fois, ce n'est pas obligatoire pour le livre et peut devenir contraignant lors de l'apprentissage de tout cela en même temps à partir de rien. Donc vous pouvez sauter cela si vous êtes un novice dans le développement web pour vous concentrer sur les parties essentielles apprises dans ce livre. 40 | 41 | ### Node et NPM 42 | 43 | Dernier point, mais pas des moindres, vous aurez besoin d'une installation de [node and npm](https://nodejs.org/en/). Les deux sont utilisés pour gérer les bibliothèques dont vous aurez besoin tout du long. Dans ce livre, vous installerez des *external node packages* via npm (node package manager). Ces *node packages* peuvent être des bibliothèques ou des frameworks en entier. 44 | 45 | Vous pouvez vérifier vos versions de node et npm en ligne de commande. Si vous n'obtenez aucune sortie sur le terminal, vous aurez au préalable besoin d'installer node et npm. Ce sont seulement mes versions au moment où j'écris ce livre : 46 | 47 | {title="Command Line",lang="text"} 48 | ~~~~~~~~ 49 | node --version 50 | *v8.9.4 51 | npm --version 52 | *v5.6.0 53 | ~~~~~~~~ 54 | 55 | ## node et npm 56 | 57 | Cette section de chapitre vous donne un petit aperçu de node et npm. Ceci n'est pas exhaustif, mais vous aurez tous les outils nécessaires. Si vous êtes familier avec les deux technologies, vous pouvez sauter cette section. 58 | 59 | Le **node package manager** (npm) vous permet d'installer des externes en ligne de commande. Ces packages peuvent être un ensemble de fonctions utilitaires, bibliothèques ou un framework complet. Ils sont les dépendances de votre application. Vous pouvez soit installer ces packages dans votre dossier node package globalement ou dans votre dossier de projet local. 60 | 61 | Les nodes packages globaux sont accessibles depuis partout au sein du terminal et vous devez les installer seulement une seule fois dans votre répertoire. Vous pouvez installer un package global en tapant dans votre terminal : 62 | 63 | {title="Command Line",lang="text"} 64 | ~~~~~~~~ 65 | npm install -g 66 | ~~~~~~~~ 67 | 68 | Le flag `-g` demande à npm d'installer le package globalement. Les packages locaux sont utilisés dans votre application. Par exemple, React en tant que bibliothèque sera un package local qui peut être requis pour l'utilisation de votre application. Vous pouvez l'installer via le terminal en tapant : 69 | 70 | {title="Command Line",lang="text"} 71 | ~~~~~~~~ 72 | npm install 73 | ~~~~~~~~ 74 | 75 | Dans le cas de React cela pourrait être : 76 | 77 | {title="Command Line",lang="text"} 78 | ~~~~~~~~ 79 | npm install react 80 | ~~~~~~~~ 81 | 82 | Le package installé apparaîtra automatiquement dans le dossier appelé *node_modules/* et sera listé dans le fichier *package.json* à côté de vos autres dépendances. 83 | 84 | Mais comment initialiser pour la première fois le dossier *node_modules/* ainsi que le fichier *package.json* pour votre projet? Il y a une commande npm pour initialiser un projet npm et ainsi un fichier *package.json*. Seulement lorsque vous avez ce fichier, vous pouvez installer des nouveaux packages locaux via npm. 85 | 86 | {title="Command Line",lang="text"} 87 | ~~~~~~~~ 88 | npm init -y 89 | ~~~~~~~~ 90 | 91 | Le flag `-y` est un raccourci pour initialisé tout par défaut dans votre *package.json*. Si vous n'utilisez pas le flag, vous devez décider de comment configurer le fichier. Après l'initialisation pour le projet npm vous êtes prêt à installer des nouveaux packages via `npm install `. 92 | 93 | 94 | Un dernier commentaire à propos du *package.json*. Le fichier vous permet de partager votre projet avec les autres développeurs sans partager tous les nodes packages. Le fichier possède toutes les références des nodes packages utilisés dans votre projet. Ces packages sont appelés dépendances. Tout le monde peut copier votre projet sans les dépendances. Les dépendances sont des références dans le *package.json*. Quelqu'un qui copie votre projet peut simplement installer tous les packages en utilisant `npm install` en ligne de commande. Le script `npm install` prend toutes les dépendances listées dans le fichier *package.json* et les installent dans le dossier *node_modules/*. 95 | 96 | Je veux traiter une commande npm supplémentaire : 97 | 98 | {title="Command Line",lang="text"} 99 | ~~~~~~~~ 100 | npm install --save-dev 101 | ~~~~~~~~ 102 | 103 | Le flag `--save-dev` indique que le node package est seulement utilisé dans le développement d'environnement. Il ne sera pas utilisé en production que lorsque vous déployez votre application sur un serveur. Quel type de node package peut-être concerné? Imaginez-vous souhaiter tester votre application avec l'aide d'un node package. Vous aurez besoin d'installer le package via npm, mais vous voulez l'exclure de votre environnement de production. Les tests devront seulement s'exécuter durant la phase de développement et en aucun cas lorsque votre application est déjà lancée en production. À ce moment si, vous ne souhaitez plus la tester. Elle devrait déjà être testée et prête à l'emploi pour vos utilisateurs. C'est seulement un cas d'utilisation parmi tant d'autres où vous souhaiterez utiliser le flag `--save-dev`. 104 | 105 | Vous rencontrerez beaucoup plus de commandes npm tout au long de votre utilisation. Mais celles-ci seront suffisants pour le moment. 106 | 107 | Il y a une chose supplémentaire qui a le mérite d'être mentionnée. Beaucoup de persones optent pour l'utilisation d'un autre package manager afin de travailler avec les nodes packages au sein de leurs applications. **Yarn** est manageur de dépendence qui fonctionne de façon très similaire qu'**npm**. Il a ses propres commandes pour performer les mêmes tâches, mais vous aurez tout aussi bien accès au npm registry. Yarn a été conçu pour résoudre quelques problèmes qu'npm n'avez pas encore résolus. Cependant, de nos jours, les deux outils évoluent très rapidement et vous pouvez choisir celui que vous voulez. 108 | 109 | ### Exercices : 110 | 111 | * installation d'un projet via npm 112 | * créer un nouveau dossier avec `mkdir ` 113 | * naviguer à l'intérieur du dossier avec `cd ` 114 | * exécuter `npm init -y` ou `npm init` 115 | * installer un package local tel que React avec `npm install react` 116 | * regarder à l'intérieur du fichier *package.json* et du dossier *node_modules/* 117 | * trouver par vous-même comment désinstaller le node package *react* 118 | * lire plus à propos de [npm](https://docs.npmjs.com/) 119 | * lire plus à propos du [yarn](https://yarnpkg.com/en/docs/) package manager 120 | 121 | ## Installation 122 | 123 | Il y a plusieurs approches pour commencer une application React. 124 | 125 | La première consiste à utiliser un CDN. Cela peut sembler plus compliqué que cela l'est. Un CDN est un [content delivery network](https://en.wikipedia.org/wiki/Content_delivery_network). Plusieurs entreprises ont des CDNs qui hébergent des fichiers publiquement pour des personnes puissent les consommer. Ces fichiers peuvent être des bibliothèques telles que React, car après tout, la bibliothèque React empaqueté est seulement un fichier JavaScript *react.js*. Elle peut être hébergée quelque part et vous pouvez la demander au sein de votre application. 126 | 127 | Comment utiliser un CDN pour débuter en React? Vous pouvez utiliser la balise inline ` 132 | 133 | ~~~~~~~~ 134 | 135 | Mais pourquoi devrez-vous utiliser un CDN quand vous disposez de npm pour installer des nodes packages tels que React? 136 | 137 | Lorsque votre application à un fichier *package.json*, vous pouvez installer *react* et *react-dom* en ligne de commande. Le prérequis est que le dossier est initialisé en tant que projet npm en utilisant `npm init -y` avec un fichier *package.json*. Vous pouvez utiliser plusieurs nodes packages en une seule ligne de commande npm. 138 | 139 | {title="Command Line",lang="text"} 140 | ~~~~~~~~ 141 | npm install react react-dom 142 | ~~~~~~~~ 143 | 144 | Cette approche est souvent utilisée pour ajouter React à une application existante qui est gérée par npm. 145 | 146 | Malheureusement ce n'est pas tout. Vous allez être obligéq de vous occuper de [Babel](http://babeljs.io/) pour faire en sorte que votre application soit compatible au JSX (la syntaxe de React) et au JavaScript ES6. Babel transpile votre code ainsi les navigateurs peuvent interpréter le JavaScript ES6 et JSX. Pas tous les navigateurs sont capables d'interpréter la syntaxe. L'installation inclut beaucoup de configuration et d'outillage. Cela peut être accablant pour les nouveaux utilisateurs de React de s'importuner avec toute la configuration. 147 | 148 | À cause de cela, Facebook introduit *create-react-app* en tant que solution React zéro configuration. Le prochain chapitre vous montrera comment installer votre application en utilisant cette outil d'initialisation. 149 | 150 | ### Exercices : 151 | 152 | * lire plus à propos des [installations React](https://reactjs.org/docs/getting-started.html) 153 | 154 | ## L'installation zéro configuration 155 | 156 | In the Road to learn React, vous utiliserez [create-react-app](https://github.com/facebookincubator/create-react-app) pour initialiser votre application. C'est un kit de démarrage orienté avec zéro configuration pour React introduit par Facebook en 2016. [96% des personnes souhaitent le recommander auprès des débutants](https://twitter.com/dan_abramov/status/806985854099062785). Dans *create-react-app* l'outillage et la configuration évolue en arrière-plan tandis que l'attention est portée sur l'implémentation de l'application. 157 | 158 | Pour démarrer, vous devrez installer le package dans votre global node packages. Après quoi, vous l'aurez toujours disponible en ligne de commande pour démarrer de nouvelles applications React. 159 | 160 | {title="Command Line",lang="text"} 161 | ~~~~~~~~ 162 | npm install -g create-react-app 163 | ~~~~~~~~ 164 | 165 | 166 | Vous pouvez vérifier la version de *create-react-app* pour vérifier que l'installation a réussi à l'aide de la ligne de commande : 167 | 168 | {title="Command Line",lang="text"} 169 | ~~~~~~~~ 170 | create-react-app --version 171 | *v1.5.1 172 | ~~~~~~~~ 173 | 174 | Maintenant vous pouvez initier votre première application React. Nous l'appelons *hackernews*, mais vous pouvez choisir un autre nom. L'initialisation prend quelques secondes. Ensuite, naviguer simplement à l'intérieur du dossier : 175 | 176 | {title="Command Line",lang="text"} 177 | ~~~~~~~~ 178 | create-react-app hackernews 179 | cd hackernews 180 | ~~~~~~~~ 181 | 182 | Maintenant vous pouvez ouvrir l'application dans votre éditeur. La structure de dossier suivant, ou à quelques variations prêtes dépendant de la version *create-react-app*, devrait vous être présentée : 183 | 184 | {title="Folder Structure",lang="text"} 185 | ~~~~~~~~ 186 | hackernews/ 187 | README.md 188 | node_modules/ 189 | package.json 190 | .gitignore 191 | public/ 192 | favicon.ico 193 | index.html 194 | manifest.json 195 | src/ 196 | App.css 197 | App.js 198 | App.test.js 199 | index.css 200 | index.js 201 | logo.svg 202 | registerServiceWorker.js 203 | ~~~~~~~~ 204 | 205 | Une petite pause sur les dossiers et les fichiers. C'est normal si vous ne les comprenez pas tous au début. 206 | 207 | * **README.md:** L'extension .md indique que le fichier est un fichier Markdown. Le Markdown est utilisé comme un langage de balisage allégé avec une syntaxe de formatage en texte brut. Plusieurs code source de projets arrivent avec un fichier *README.md* pour donner des instructions initiales à propos du projet. Finalement lors de l'envoi de votre projet auprès d'une plateforme telle que Github, le fichier *README.md* montrera son contenu de manière évidente lorsque vous accédez au dépôt. Comme vous avez utilisé *create-react-app*, votre *README.md* devrait être le même que celui affiché dans le dépôt officiel [dépôt GithHub create-react-app](https://github.com/facebookincubator/create-react-app). 208 | 209 | * **node_modules/:** Le dossier a tous les nodes packages qui sont installés via npm. Puisque vous avez utilisé *create-react-app*, iL devrait déjà avoir plusieurs nodes modules installés pour vous. Habituellement, vous ne toucherez jamais à ce dossier, mais seulement installerez et désinstallerez des nodes packages avec npm depuis la ligne de commande. 210 | 211 | * **package.json:** Le fichier vous affiche une liste de dépendance de nodes packages et d'autre configurations de projet. 212 | 213 | * **yarn.lock:** Par défaut, si Yarn est installé, create-react-app utilise Yarn en tant que package manager. Si vous n'avez pas installé Yarn alors create-react-app utilisera le Node package manager. si vous disposez de Yarn et Node en package manager d'installé vous pouvez utiliser le Node package manager en ajoutant --use-npm à la commande create-react-app. Vous n'avez pas besoin de prêter attention à ce fichier pour l'heure. Si vous voulez en apprendre plus à propos de la migration du Node package manager vers le Yarn package manager, se conférer https://yarnpkg.com/en/docs/migrating-from-npm. 214 | 215 | * **.gitignore:** Le fichier indique tous les fichiers et dossiers qui ne devront pas être ajoutés à votre dépôt git lors de l'utilisation de git. Ils devraient seulement être présent au sein de votre projet local. Le dossier *node_modules/* en est un exemple d'utilisation. En effet, c'est suffisant de partager le fichier *package.json* avec vos paires pour leur permettre d'installer toutes les dépendances par eux-mêmes sans partager la totalité du dossier de dépendance. 216 | 217 | * **public/:** Le dossier possède tous vos fichiers racines, tel que *public/index.html*. Cet index est celui affiché lors du développement de votre app sur localhost:3000. Le boilerplate prend soin de relier cet index avec l'ensemble des scripts présents dans *src/*. 218 | 219 | * **build/** Le dossier sera créé lors de la phase de build du projet pour une mise en production. Il possède tous nos fichiers de production lors de la création de votre projet pour une mise en production. Tout votre code écrit dans les dossiers *src/* et *public/* est empaqueté au sein de quelques fichiers lors de la phase de build de votre projet et placé au sein du dossier de build. 220 | 221 | * **manifest.json** et **registerServiceWorker.js:** ne prêtez pas attention à ce que font ces fichiers pour le moment, nous n'en auront pas l'utilité dans ce projet. 222 | 223 | Malgré tout, vous n'aurez pas la nécessité de toucher les fichiers et dossiers mentionnés. Pour démarrer la seule chose dont vous aurez besoin est localisé dans le dossier *src/*. L'attention principale se porte sur le fichier *src/App.js* pour implémenter les composants React. Il sera utilisé pour implémenter votre application, mais plus tard vous pourriez vouloir séparer vos composants en plusieurs fichiers tandis que chaque fichier maintient un seul ou quelques composants. 224 | 225 | De plus, vous trouverez un fichier *src/App.test.js* pour vos tests et un fichier *src/index.js* en tant que point d'entrée au monde de React. Vous serez amené à connaitre les deux fichiers dans un prochain chapitre. En plus, il y a un fichier *src/index.css* est un fichier *src/App.css* pour styliser votre application de façon générale et vos composants. Les composants arrivent tous avec un fichier de style par défaut lorsque vous les ouvrez. 226 | 227 | L'application *create-react-app* est un projet npm. Vous pouvez utiliser npm pour installer et désinstaller des nodes packages de votre projet. De plus, il embarque les scripts npm suivants disponibles en ligne de commande : 228 | 229 | {title="Command Line",lang="text"} 230 | ~~~~~~~~ 231 | # Lance l'application sur http://localhost:3000 232 | npm start 233 | 234 | # Lance les tests 235 | npm test 236 | 237 | # Construit l'application pour la mise en production 238 | npm run build 239 | ~~~~~~~~ 240 | 241 | Les scripts sont définis dans votre *package.json*. Votre application React passe-partout est maintenant initialisée. La partie existante arrive avec les exercices pour finalement lancer votre application initialisée au sein du navigateur. 242 | 243 | ### Exercices : 244 | 245 | * `npm start` pour démarrer votre application et visionner l'application dans votre navigateur (vous pouvez arrêter la commande en tapant Ctrl + C) 246 | * lancer le script `npm test` interactif 247 | * lancer le script `npm run build` et vérifier qu'un dossier *build/* a été ajouté à votre projet (vous pouvez de nouveau le supprimer par la suite; noter que le dossier build peut être utilisé plus tard pour [déployer votre application](https://www.robinwieruch.de/deploy-applications-digital-ocean/)) 248 | * vous familiarisez avec la structure de dossier 249 | * vous familiarisez avec le contenu des fichiers 250 | * lire plus à propos [des scripts npm et de create-react-app](https://github.com/facebookincubator/create-react-app) 251 | 252 | ## Introduction au JSX 253 | 254 | Maintenant vous allez faire connaissance avec le JSX. C'est une syntaxe utilisée dans React. Comme mentionné avant, *create-react-app* a déjà mis en place un boilerplate d'application pour vous. L'ensemble des fichiers arrivent avec des implémentations par défaut. Il est temps de plonger dans le code source. Le seul fichier que nous manipulerons pour débuter sera le fichier *src/App.js*. 255 | 256 | {title="src/App.js",lang=javascript} 257 | ~~~~~~~~ 258 | import React, { Component } from 'react'; 259 | import logo from './logo.svg'; 260 | import './App.css'; 261 | 262 | class App extends Component { 263 | render() { 264 | return ( 265 |
266 |
267 | logo 268 |

Welcome to React

269 |
270 |

271 | To get started, edit src/App.js and save to reload. 272 |

273 |
274 | ); 275 | } 276 | } 277 | 278 | export default App; 279 | ~~~~~~~~ 280 | 281 | Ne vous laissez distraire par les déclarations d'import/export et de class. Ce sont des fonctionnalités de JavaScript ES6. À ce titre, nous les réétudierons dans un prochain chapitre. 282 | 283 | Dans le fichier vous avez une **React ES6 class component** avec le nom de l'application. C'est une déclaration de composant. Globalement après vous avez déclaré un composant, vous pouvez utiliser ce dernier en tant qu'élément depuis partout dans votre application. Il produira une **instance** de votre **component** ou en d'autres termes: le composant sera instancié. 284 | 285 | L'**element** retourné est spécifié dans la méthode `render()`. Les éléments sont la résultant de pourquoi les composants sont créés. C'est essentiel de comprendre la différence entre un composant, une instance d'un composant et un élément. 286 | 287 | Prochainement, vous verrez où l'App component est instancié. Sans quoi vous ne pourriez apprécier le rendu en sortit du navigateur, n'est-ce pas? L'App component est seulement la déclaration, mais non son utilisation. Vous instancierait le composant quelque part dans votre JSX avec ``. 288 | 289 | Le contenu dans le bloc de rendu apparaît assez similaire à de l'HTML, mais c'est du JSX. JSX vous permet de mélanger HTML et JavaScript. C'est puissant encore un peu déroutant quand on avait pour habitude de séparer l'HTML du JavaScript. C'est pourquoi, un bon point pour débuter consiste à utiliser de l'HTML basique à l'intérieur de votre JSX. Au tout début, ouvrez le fichier `App.js` et supprimez tout le code HTML inutile comme illustré ci-dessous. 290 | 291 | {title="src/App.js",lang=javascript} 292 | ~~~~~~~~ 293 | import React, { Component } from 'react'; 294 | import './App.css'; 295 | 296 | class App extends Component { 297 | render() { 298 | return ( 299 |
300 |

Welcome to the Road to learn React

301 |
302 | ); 303 | } 304 | } 305 | 306 | export default App; 307 | ~~~~~~~~ 308 | 309 | Maintenant, vous retournez seulement de l'HTML dans votre méthode `render()` sans JavaScript. Laissez-moi définir le "Welcome to the Road to learn React" en tant que variable. Une variable peut être utilisée dans votre JSX en utilisant les accolades. 310 | 311 | {title="src/App.js",lang=javascript} 312 | ~~~~~~~~ 313 | import React, { Component } from 'react'; 314 | import './App.css'; 315 | 316 | class App extends Component { 317 | render() { 318 | # leanpub-start-insert 319 | var helloWorld = 'Welcome to the Road to learn React'; 320 | # leanpub-end-insert 321 | return ( 322 |
323 | # leanpub-start-insert 324 |

{helloWorld}

325 | # leanpub-end-insert 326 |
327 | ); 328 | } 329 | } 330 | 331 | export default App; 332 | ~~~~~~~~ 333 | 334 | Cela devrait fonctionner quand vous démarr er votre application à l'aide de la commande `npm start` de nouveau. 335 | 336 | Qui plus est vous devriez avoir remarqué l'attribut `className`. Il réfléchit l'attribut HTML standard `class`. Due à des raisons techniques, JSX a remplacé une poignée d'attributs HTML internes. Vous pouvez trouver tous les [attributs HTML supportés au sein de la documentation React](https://reactjs.org/docs/dom-elements.html#all-supported-html-attributes). Ils suivent tous la convention camelCase. Dans votre apprentissage à React, vous rencontrerez quelques attributs spécifiques JSX supplémentaire. 337 | 338 | ### Exercices : 339 | 340 | * Définir plus de variables et les rendre au sein de votre JSX 341 | * utiliser un objet complexe pour représenter un utilisateur avec prénom et nom 342 | * rendre les propriétés de l'utilisateur dans votre JSX 343 | * Lire plus à propos de [JSX](https://reactjs.org/docs/introducing-jsx.html) 344 | * Lire plus à propos des [composants React, éléments et instances](https://reactjs.org/blog/2015/12/18/react-components-elements-and-instances.html) 345 | 346 | ## ES6 const et let 347 | 348 | Je devine que vous avez remarqué que nous avons déclaré la variable `helloWorld` avec une déclaration `var`. JavaScript ES6 arrive avec deux alternatives supplémentaires pour déclarer vos variables : `const` et `let`. En JavaScript ES6, vous trouverez rarement `var` dorénavant. 349 | 350 | Une variable déclarée avec `const` ne peut être réassignée ou redéclarée. Il ne peut être muté (changé, modifié). Vous forcez les structures de données immutables en utilisant cela. Une fois la structure de données défini, vous ne pouvez en changer. 351 | 352 | {title="Code Playground",lang="javascript"} 353 | ~~~~~~~~ 354 | // pas permis 355 | const helloWorld = 'Welcome to the Road to learn React'; 356 | helloWorld = 'Bye Bye React'; 357 | ~~~~~~~~ 358 | 359 | Une variable déclarée avec `let` peut être modifiée. 360 | 361 | {title="Code Playground",lang="javascript"} 362 | ~~~~~~~~ 363 | // permis 364 | let helloWorld = 'Welcome to the Road to learn React'; 365 | helloWorld = 'Bye Bye React'; 366 | ~~~~~~~~ 367 | 368 | Vous l'utiliserez quand vous aurez besoin de réassigner une variable. 369 | 370 | Cependant, vous devez être vigilant avec `const`. Une variable déclarée avec `const` ne peut pas être modifiée. Mais quand la variable est un tableau d'objet, la valeur contenu peut-être modifié. La valeur contenue n'est pas immutable. 371 | 372 | {title="Code Playground",lang="javascript"} 373 | ~~~~~~~~ 374 | // permis 375 | const helloWorld = { 376 | text: 'Welcome to the Road to learn React' 377 | }; 378 | helloWorld.text = 'Bye Bye React'; 379 | ~~~~~~~~ 380 | 381 | Mais quand utiliser chaque déclaration? Il y a différents avis à propos de leur utilisation. Je suggère d'utiliser `const` à chaque fois vous le pouvez. Cela indique que vous souhaiter conserver votre structure de données immutable même si les valeurs des objets et tableaux peuvent être modifiés. Si vous voulez modifier votre variable préconisée `let`. 382 | 383 | L'immutabilité est adoptée par React et son écosystème. C'est pourquoi `const` devra être votre choix par défaut quand vous définissez une variable. Encore que, dans les objets complexes les valeurs à l'intérieur peuvent être modifiées. Soyez attentif à propos de ce comportement. 384 | 385 | Dans votre application, vous devriez utiliser `const` plutôt `var`. 386 | 387 | {title="src/App.js",lang=javascript} 388 | ~~~~~~~~ 389 | import React, { Component } from 'react'; 390 | import './App.css'; 391 | 392 | class App extends Component { 393 | render() { 394 | # leanpub-start-insert 395 | const helloWorld = 'Welcome to the Road to learn React'; 396 | # leanpub-end-insert 397 | return ( 398 |
399 |

{helloWorld}

400 |
401 | ); 402 | } 403 | } 404 | 405 | export default App; 406 | ~~~~~~~~ 407 | 408 | ### Exercices : 409 | 410 | * lire plus à propos [ES6 const](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const) 411 | * lire plus à propos [ES6 let](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let) 412 | * En savoir plus à propos des structures de données immutables 413 | * Pourquoi cela a du sens dans la programmation en général 414 | * Pourquoi sont-elles utilisées dans React et son écosystème 415 | 416 | ## ReactDOM 417 | 418 | Avant de continuer avec l'App component, vous devriez vouloir voir où c'est utilisé. C'est localisé dans votre point d'entrée du monde de React : le fichier *src/index.js*. 419 | 420 | {title="src/index.js",lang=javascript} 421 | ~~~~~~~~ 422 | import React from 'react'; 423 | import ReactDOM from 'react-dom'; 424 | import App from './App'; 425 | import './index.css'; 426 | 427 | ReactDOM.render( 428 | , 429 | document.getElementById('root') 430 | ); 431 | ~~~~~~~~ 432 | 433 | Globalement `ReactDOM.render()` utilise un noeud du DOM dans votre HTML pour le remplacer avec votre JSX. C'est comme cela que vous pouvez facilement intégrer React dans toutes applications étrangères. Il n'est pas interdit d'utiliser `ReactDOM.render()` plusieurs fois au travers de votre application. Vous pouvez l'utiliser à différents endroits pour initialiser de la simple syntaxe JSX, un composant React, plusieurs composants React ou toute une application. Mais pour une simple application React vous l'utiliserez seulement une seule fois pour initialiser l'entièreté de votre arbre de composant. 434 | 435 | `ReactDOM.render()` attend deux arguments. Le premier argument est du JSX qui sera rendu. Le second argument spécifie la localisation où l'application React prendra place dans votre HTML. Il attend un élément avec un `id='root'`. Vous pouvez dès lors ouvrir votre fichier pour trouver *public/index.html* l'attribut id. 436 | 437 | L'implémentation de `ReactDOM.render()` prend déjà votre App component. Cependant, ce serait intéressant de passer du JSX le plus simplifié tant que cela reste du JSX. Cela n'a pas nécessité d'être une instanciation de composant. 438 | 439 | {title="Code Playground",lang=javascript} 440 | ~~~~~~~~ 441 | ReactDOM.render( 442 |

Hello React World

, 443 | document.getElementById('root') 444 | ); 445 | ~~~~~~~~ 446 | 447 | ### Exercices : 448 | 449 | * ouvrir *public/index.html* pour voir où les applications React prennent place à l'intérieur de votre HTML 450 | * lire plus à propos [du rendu des éléments dans React](https://reactjs.org/docs/rendering-elements.html) 451 | 452 | ## Hot Module Replacement 453 | 454 | Il y a une chose que vous pouvez faire au sein du fichier *src/index.js* pour améliorer votre expérience de développement en tant que développeur. Mais c'est optionnel et vous ne devrez pas vous en préoccuper au début de votre apprentissage avec React. 455 | 456 | *create-react-app* dispose déjà de l'avantage que le navigateur rafraichisse automatiquement la page quand vous modifiez le code source. Essayez en changeant la variable `helloWorld` dans votre fichier *src/App.js*. Le navigateur devrait rafraichir la page. Cependant il y a une meilleure façon de le faire. 457 | 458 | Le Hot Module Replacement (HMR) est un outil pour recharger votre application dans le navigateur. Le navigateur n'a pas nécessité de performer un rafraichissement de page. Vous pouvez facilement l'activer dans create-react-app*. Dans votre *src/index.js*, votre point d'entrée pour React, vous devez ajouter une petite configuration. 459 | 460 | {title="src/index.js",lang=javascript} 461 | ~~~~~~~~ 462 | import React from 'react'; 463 | import ReactDOM from 'react-dom'; 464 | import App from './App'; 465 | import './index.css'; 466 | 467 | ReactDOM.render( 468 | , 469 | document.getElementById('root') 470 | ); 471 | 472 | # leanpub-start-insert 473 | if (module.hot) { 474 | module.hot.accept(); 475 | } 476 | # leanpub-end-insert 477 | ~~~~~~~~ 478 | 479 | C'est tout! Essayez de nouveau de changer la variable `helloWorld` dans votre fichier *src/App.js*. Le navigateur ne dervrait pas performer de rafraichissement de page, mais l'application se recharge et affiche la nouvelle sortie correctement. HMR vient avec de nombreux avantages : 480 | 481 | Imaginez-vous êtes en train de debugger votre code avec des déclarations de `console.log()`. Ces déclarations resteront dans votre console développeur, même si vous modifiez votre code, parce que le navigateur ne rafraichit plus la page maintenant. Cela peut être un atout à des fins de debug. 482 | 483 | Dans une application grandissant le rafraichissement de page ralenti votre productivité. Vous êtes obligé d'attendre que la page charge. Un rechargement de page peut prendre quelques secondes au sein d'une importante application. HMR repousse ce désavantage. 484 | 485 | Le plus grand bénéfice c'est que vous pouvez conserver l'état de l'application avec HMR. Imaginez-vous avez une boîte de dialogue dans votre application avec plusieurs étapes et vous êtes à l'étape 3. Globalement c'est un assistant. Sans HMR vous souhaiteriez changer le code source et votre navigateur rafraichirait la page. Vous devriez rouvrir la boîte de dialogue encore une fois et naviguer de l'étape 1 à 3. Avec HMR votre boîte de dialogue reste ouverte à l'étape 3. Il conserve l'état de l'application même si le code source change. L'application elle-même se recharge, mais pas la page. 486 | 487 | ### Exercises : 488 | 489 | * Modifier votre *src/App.js* code source plusieurs fois et vérifier l'HMR en action 490 | * Regarder les 10 premières minutes du [Live de React: Hot Reloading avec Time Travel](https://www.youtube.com/watch?v=xsSnOQynTHs) par Dan Abramov 491 | 492 | 493 | ## JavaScript complex en JSX 494 | 495 | Maintenant retourner à votre App component. Jusqu'à présent, vous rendez quelques variables primitives dans votre JSX. Maintenant vous allez commencer par rendre une liste d'objets. Pour débuter, la liste sera un échantillon de données, mais plus tard vous aller chercher les données depuis une [API](https://www.robinwieruch.de/what-is-an-api-javascript/) externe. Cela sera beaucoup plus passionnant. 496 | 497 | Tout d'abord vous devez définir une liste d'objets. 498 | 499 | {title="src/App.js",lang=javascript} 500 | ~~~~~~~~ 501 | import React, { Component } from 'react'; 502 | import './App.css'; 503 | 504 | # leanpub-start-insert 505 | const list = [ 506 | { 507 | title: 'React', 508 | url: 'https://reactjs.org/', 509 | author: 'Jordan Walke', 510 | num_comments: 3, 511 | points: 4, 512 | objectID: 0, 513 | }, 514 | { 515 | title: 'Redux', 516 | url: 'https://redux.js.org/', 517 | author: 'Dan Abramov, Andrew Clark', 518 | num_comments: 2, 519 | points: 5, 520 | objectID: 1, 521 | }, 522 | ]; 523 | # leanpub-end-insert 524 | 525 | class App extends Component { 526 | ... 527 | } 528 | ~~~~~~~~ 529 | 530 | L'échantillon de données reflétera les données que nous irons chercher plus tard depuis l'API. Un objet dans la liste possède un titre, une url et un auteur. Qui plus est l'objet dispose d'un identificateur, de points (indique comment un article est populaire) et d'un nombre de commentaires. 531 | 532 | Maintenant vous pouvez utiliser la fonctionnalité native `map` dans votre JSX. Cela permet d'itérer sur votre liste d'objets et de les afficher. Encore une fois vous utiliserez les accolades pour encapsuler les expressions JavScript dans votre JSX. 533 | 534 | {title="src/App.js",lang=javascript} 535 | ~~~~~~~~ 536 | class App extends Component { 537 | render() { 538 | return ( 539 |
540 | # leanpub-start-insert 541 | {list.map(function (item) { 542 | return
{item.title}
; 543 | })} 544 | # leanpub-end-insert 545 |
546 | ); 547 | } 548 | } 549 | 550 | export default App; 551 | ~~~~~~~~ 552 | 553 | Le fait d'utiliser le JavaScript dans l'HTML est assez puissant en JSX. Habituellement, il vous est conseillé d'utiliser `map` pour convertir une liste d'objets en une autre liste d'objets. Cette fois vous utilisez `map` pour convertir une liste d'objets en éléments HTML. 554 | 555 | Jusqu'à maintenant, seul le `title` a été affiché à chaque fois. Essayons d'afficher un peu plus de propriétés de l'objet. 556 | 557 | {title="src/App.js",lang=javascript} 558 | ~~~~~~~~ 559 | class App extends Component { 560 | render() { 561 | return ( 562 |
563 | # leanpub-start-insert 564 | {list.map(function (item) { 565 | return ( 566 |
567 | 568 | {item.title} 569 | 570 | {item.author} 571 | {item.num_comments} 572 | {item.points} 573 |
574 | ); 575 | })} 576 | # leanpub-end-insert 577 |
578 | ); 579 | } 580 | } 581 | 582 | export default App; 583 | ~~~~~~~~ 584 | 585 | Vous pouvez remarquer la fonction `map` est simplement en ligne dans votre JSX. Chaque propriété de l'objet est affichée dans une balise ``. De plus, la propriété url de l'objet est utilisée dans l'attribut `href` de la balise ancre. 586 | 587 | React fera tout le travail pour vous et affichera chaque objet. Mais vous devez ajouter un helper pour que React atteigne son plein potentiel et qu'il améliore ses performances. Vous allez devoir assigner un attribut clé à chaque élément de la liste. Ainsi React sera capable d'identifier les éléments ajoutés, changés et supprimés quand la liste change. L'échantillon d'éléments arrive d'ores et déjà avec un identifieur. 588 | 589 | {title="src/App.js",lang=javascript} 590 | ~~~~~~~~ 591 | {list.map(function (item) { 592 | return ( 593 | # leanpub-start-insert 594 |
595 | # leanpub-end-insert 596 | 597 | {item.title} 598 | 599 | {item.author} 600 | {item.num_comments} 601 | {item.points} 602 |
603 | ); 604 | })} 605 | ~~~~~~~~ 606 | 607 | Vous devrez vous assurer que l'attribut `key` est un identifiant stable. Ne faites pas l'erreur d'utiliser l'index de l'objet dans un tableau. L'index de tableau n'est pas stable du tout. Par exemple, quand la liste change son ordonnancement, React aura des difficultés à identifier les objets correctement. 608 | 609 | {title="src/App.js",lang=javascript} 610 | ~~~~~~~~ 611 | // ne pas faire cela 612 | {list.map(function (item, key) { 613 | return ( 614 |
615 | ... 616 |
617 | ); 618 | })} 619 | ~~~~~~~~ 620 | 621 | Vous affichez les deux listes d'objets maintenant. Vous pouvez démarrer votre application, ouvrir votre navigateur et voir les deux objets de la liste affichés. 622 | 623 | ### Exercices : 624 | 625 | * lire plus à propos des [listes et clés de React](https://reactjs.org/docs/lists-and-keys.html) 626 | * Récapitulatif des [fonctionnalités natives et standard du tableau en JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/) 627 | * Utiliser plus d'expression JavaScript de vous-même en JXS 628 | 629 | ## ES6 les fonctions fléchées 630 | 631 | JavaScript ES6 introduit les fonctions fléchées. Une expression de fonction fléchée est plus courte qu'une expression de fonction. 632 | 633 | {title="Code Playground",lang="javascript"} 634 | ~~~~~~~~ 635 | // function expression 636 | function () { ... } 637 | 638 | // arrow function expression 639 | () => { ... } 640 | ~~~~~~~~ 641 | 642 | Mais vous devez rester conscient de ces fonctionnalités. L'un d'eux dispose d'un comportement différent avec l'objet `this`. Une expression de fonction définie toujours son propre objet `this`. Tandis que les expressions de fonction fléchée possèdent encore l'objet `this` du contexte parent. Ne soyez pas désorientés lorsque vous utiliserez `this` à l'intérieur d'une fonction fléchée. 643 | 644 | Il y a un autre point intéressant à propos des fonctions fléchées concernant les parenthèses. Vous pouvez supprimer les parenthèses quand la fonction possède seulement un argument, mais vous êtes obligés de les conserver le cas contraire. 645 | 646 | {title="Code Playground",lang="javascript"} 647 | ~~~~~~~~ 648 | // permis 649 | item => { ... } 650 | 651 | // permis 652 | (item) => { ... } 653 | 654 | // pas permis 655 | item, key => { ... } 656 | 657 | // permis 658 | (item, key) => { ... } 659 | ~~~~~~~~ 660 | 661 | Cependant, jetons à coup d'oeil à la fonction `map`. Vous pouvez l'écrire de façon plus concise avec la fonction fléchée ES6. 662 | 663 | {title="src/App.js",lang=javascript} 664 | ~~~~~~~~ 665 | # leanpub-start-insert 666 | {list.map(item => { 667 | # leanpub-end-insert 668 | return ( 669 |
670 | 671 | {item.title} 672 | 673 | {item.author} 674 | {item.num_comments} 675 | {item.points} 676 |
677 | ); 678 | })} 679 | ~~~~~~~~ 680 | 681 | De plus, vous pouvez supprimer le *block body*, c'est-à-dire les accolades, de la fonction fléchée ES6. Dans un *concise body* un implicite `return` est attaché. Ainsi vous pouvez supprimer la déclaration `return`. Cela s'utilisera assez souvent dans le livre, donc soyez sûre de bien comprendre la différence entre un *block body* et un *concise body* lorsque vous utilisez des fonctions fléchées. 682 | 683 | {title="src/App.js",lang=javascript} 684 | ~~~~~~~~ 685 | # leanpub-start-insert 686 | {list.map(item => 687 | # leanpub-end-insert 688 |
689 | 690 | {item.title} 691 | 692 | {item.author} 693 | {item.num_comments} 694 | {item.points} 695 |
696 | # leanpub-start-insert 697 | )} 698 | # leanpub-end-insert 699 | ~~~~~~~~ 700 | 701 | Votre JSX apparaît plus concis et lisible maintenant. Il omet la déclaration de `function`, les accolades et la déclaration du `return`. Au lieu de cela le développeur peut rester concentré sur les détails d'implémentation. 702 | 703 | ### Exercices : 704 | 705 | * lire plus à propos des [fonctions fléchées ES6](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions) 706 | 707 | ## ES6 Classes 708 | 709 | JavaScript ES6 introduit les classes. Une classe est communément utilisé dans des langages de programmation orientés objet. JavaScript était et est très souple dans ses paradigmes de programmation. Vous pouvez faire de la programmation fonctionnelle et orientée objet côte à côte avec leur cas d'utilisation particulier. 710 | 711 | Même si React adhère à la programmation fonctionnelle, par exemple au travers des structures de données immutables, les classes sont aussi utilisées pour déclarer des composants. Elles sont appelées les composants de classe ES6. React mélange les meilleurs des deux paradigmes. 712 | 713 | Laissons nous considérer la classe Developer suivante pour examiner une classe JavaScript ES6 sans penser composant. 714 | 715 | {title="Code Playground",lang="javascript"} 716 | ~~~~~~~~ 717 | class Developer { 718 | constructor(firstname, lastname) { 719 | this.firstname = firstname; 720 | this.lastname = lastname; 721 | } 722 | 723 | getName() { 724 | return this.firstname + ' ' + this.lastname; 725 | } 726 | } 727 | ~~~~~~~~ 728 | 729 | Une classe dispose d'un constructeur pour la rendre instanciable. Le constructeur peut prendre plusieurs arguments pour les assigner à l'instance de la classe. De plus, une classe peut définir des fonctions. Du fait que la fonction est associée à une classe, elle est appelée une méthode. Souvent elle est référencée en tant que méthode de classe. 730 | 731 | La classe Developer est seulement une déclaration de classe. Vous pouver créer plusieurs instances de classe en l'invoquant. C'est similaire pour une classe ES6 de composant, qui a une déclaration, mais vous devez l'utiliser autres parts pour l'instancier. 732 | 733 | Regardons comment vous devez instancier la classe et comment vous pouvez utiliser ses méthodes. 734 | 735 | {title="Code Playground",lang="javascript"} 736 | ~~~~~~~~ 737 | const robin = new Developer('Robin', 'Wieruch'); 738 | console.log(robin.getName()); 739 | // output: Robin Wieruch 740 | ~~~~~~~~ 741 | 742 | React utilise les classes JavaScript ES6 pour les classes de composants ES6. Vous utilisez d'ores et déjà la classe de composant ES6. 743 | 744 | {title="src/App.js",lang=javascript} 745 | ~~~~~~~~ 746 | import React, { Component } from 'react'; 747 | 748 | ... 749 | 750 | class App extends Component { 751 | render() { 752 | ... 753 | } 754 | } 755 | ~~~~~~~~ 756 | 757 | La classe App étend `Component`. Globalement, vous déclarez le composant App, mais il s'étend d'un autre composant. Qu'est-ce que le terme étendre signifie-t-il? En programmation orientée objet vous avez le principe d'héritage. C'est utilisé pour passer des fonctionnalités d'une classe à l'autre. 758 | 759 | La classe App étend les fonctionnalités à partir de la classe `Component`. Pour être plus précis, elle hérite des fonctionnalités de la classe `Component`. La classe `Component` est utilisée pour étendre une classe ES6 basique en classe composant ES6. Elle possède toutes les fonctionnalités qu'un composant React a besoin d'avoir. La méthode `render` est une de ces fonctionnalités que vous avez déjà utilisées. Vous apprendrez un peu plus tard les autres méthodes de la classe `Component`. 760 | 761 | La classe `Component` encapsule tous les détails d'implémentation du composant React. Permettant aux développeurs d'utiliser des classes en tant que composants dans React. 762 | 763 | Les méthodes qu'un React `Component` expose sont l'interface publique. L'une de ces méthodes a besoin d'être surchargé, les autres n'ont pas la nécessité. Vous en apprendrez davantage à propos de cette dernière quand le livre abordera les méthodes du cycle de vie dans un prochain chapitre. La méthode `render()` à besoin d'être surchargé, parce qu'elle définit la sortie d'un `Component` React. Elle doit être définie. 764 | 765 | Maintenant vous connaissez les bases autour des classes JavaScript ES6 et de comment elles sont utilisées dans React pour les étendre à des composants. Vous en apprendrez plus au sujet des méthodes de composant quand le livre décrira les méthodes du cycle de vie de React. 766 | 767 | ### Exercices : 768 | 769 | * lire plus à propos des [classes ES6](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Classes) 770 | * lire plus à propos [des fondamentaux de JavaScript nécessaire avant l'apprentissage de React](https://www.robinwieruch.de/javascript-fundamentals-react-requirements/) 771 | 772 | {pagebreak} 773 | 774 | Vous avez appris à initier votre propre application React! Récapitulons les derniers chapitres : 775 | 776 | * React 777 | * create-react-app démarre une application React. 778 | * JSX mélange totalement l'HTML et le JavaScript dans le but de définir la sortie des composants React dans leurs méthodes render. 779 | * Composants, instances et éléments sont différentes choses dans React 780 | * `ReactDOM.render()` est un point d'entrée pour une application React pour attacher React à l'intérieur du DOM 781 | * Les fonctionnalités natives de JavaScript peuvent être utilisés en JSX 782 | * map peut être utilisé pour rendre une liste d'objet en tant qu'éléments HTML 783 | * ES6 784 | * Les déclarations de variables avec `const` et `let` peuvent être utilisées pour des cas d'utilisation spécifiques 785 | * Utiliser const par-dessus let dans les applications React 786 | * Les fonctions fléchées peuvent être utilisées pour conserver vos fonctions concises 787 | * Les classes sont utilisées pour définir les composants dans React en les étendant 788 | 789 | Il peut être intéressant de faire une pause à ce niveau-ci. Intérioriser les acquis et les appliquer de façon autonome. Vous pouvez trouver le code source dans le [dépôt officiel](https://github.com/rwieruch/hackernews-client/tree/4.1). 790 | -------------------------------------------------------------------------------- /manuscript/chapter4.md: -------------------------------------------------------------------------------- 1 | # Organisation du code et tests 2 | 3 | Ce chapitre se concentrera sur des sujets importants pour conserver un code maintenable dans une application scalable. Vous apprendrez à organiser le code adopter les meilleurs pratiques lors de la structuration de vos dossiers et fichiers. Un autre aspect vous apprendrez à tester, ce qui est primordial pour conserver un code robuste. Enfin, vous allez apprendre à utiliser un outil très utile pour le deboggage de vos applications React. La majeure partie du chapitre prendra du recul sur l'aspect pratique de l'application et expliquera quelques-uns de ces sujets pour vous. 4 | 5 | ## ES6 Modules : Import et Export 6 | 7 | En JavaScript ES6 vous pouvez importer et exporter les fonctionnalités de modules. Ces fonctionnalités peuvent être des fonctions, classes, composants, constantes et autres. Globalement tous ce que vous pouvez assigner à une variable. Les modules peuvent être de simples fichiers ou des dossiers complets avec un fichier d'index en tant que point d'entrée. 8 | 9 | Au début du livre, après que vous ayez démarré votre application avec *create-react-app*, vous avez déjà plusieurs déclarations d'`import` et d'`export` au sein de vos fichiers initiaux. Maintenant il est temps de les expliquer. 10 | 11 | Les déclarations d'`import` et d'`export` vous aident à partager le code au travers de multiples fichiers. Avant il y avait déjà plusieurs solutions pour çà au sein de l'environnement JavaScript. C'était un bazar, car vous souhaitez suivre une façon standardisée plutôt que d'avoir plusieurs approches pour la même chose. Maintenant c'est un comportement natif depuis JavaScript ES6. 12 | 13 | De plus ces déclarations adhèrent à la séparation de code. Vous distribuez votre code au travers de multiples fichiers pour le garder réutilisable et maintenable. Réutilisable car vous pouvez importer un morceau de code dans plusieurs fichiers. Maintenable car vous avez qu'une seule source où vous maintenez le morceau de code. 14 | 15 | Enfin mais pas des moindres, il vous aide à penser en matière d'encapsulation de code. Pas toutes les fonctionnalités ont la nécessité d'être exportées depuis un fichier. Certaines de ces fonctionnalités devrait seulement être utilisé dans le fichier où ils ont été définies. Les exports d'un fichier sont simplement l'API publique du fichier. Seules les fonctionnalités exportées sont disponibles pour être réutilisé ailleurs. Cela suit la meilleure pratique de l'encapsulation. 16 | 17 | Mais mettons-nous à la pratique. Comment ces déclarations d'`import` et d'`export` fonctionnent-ils? Les exemples suivants présentent les déclarations en partageant une ou plusieurs variables au travers de deux fichiers. À la fin, l'approche peut être mise à l'échelle pour de multiples fichiers et peut partager plus que de simples variables. 18 | 19 | Vous pouvez exporter une ou plusieurs variables. C'est appelé un export nommé (named export). 20 | 21 | {title="Code Playground: file1.js",lang="javascript"} 22 | ~~~~~~~~ 23 | const firstname = 'robin'; 24 | const lastname = 'wieruch'; 25 | 26 | export { firstname, lastname }; 27 | ~~~~~~~~ 28 | 29 | Et les importer dans un autre fichier avec un chemin relatif au premier fichier 30 | 31 | {title="Code Playground: file2.js",lang="javascript"} 32 | ~~~~~~~~ 33 | import { firstname, lastname } from './file1.js'; 34 | 35 | console.log(firstname); 36 | // output: robin 37 | ~~~~~~~~ 38 | 39 | Vous pouvez aussi importer toutes les variables exporter depuis un autre fichier comme étant un seul objet. 40 | 41 | {title="Code Playground: file2.js",lang="javascript"} 42 | ~~~~~~~~ 43 | import * as person from './file1.js'; 44 | 45 | console.log(person.firstname); 46 | // output: robin 47 | ~~~~~~~~ 48 | 49 | Les imports peuvent avoir un alias. Cela peut arriver que vous importez des fonctionnalités de divers fichiers et qu'ils ont le même nom d'export. C'est pour cela que vous pouvez utiliser un alias. 50 | 51 | {title="Code Playground: file2.js",lang="javascript"} 52 | ~~~~~~~~ 53 | import { firstname as username } from './file1.js'; 54 | 55 | console.log(username); 56 | // output: robin 57 | ~~~~~~~~ 58 | 59 | Dernier point, mais pas des moindres il existe la déclaration `default`. Elle peut être utilisée pour plusieurs cas d'utilisation : 60 | 61 | * exporter et importer une seule fonctionnalité 62 | * mettre en exergue la fonctionnalité principale de l'API exporté d'un module 63 | * avoir une fonctionnalité d'import de secours 64 | 65 | {title="Code Playground: file1.js",lang="javascript"} 66 | ~~~~~~~~ 67 | const robin = { 68 | firstname: 'robin', 69 | lastname: 'wieruch', 70 | }; 71 | 72 | export default robin; 73 | ~~~~~~~~ 74 | 75 | Vous pouvez omettre les accolades pour l'import afin d'importer le default export. 76 | 77 | {title="Code Playground: file2.js",lang="javascript"} 78 | ~~~~~~~~ 79 | import developer from './file1.js'; 80 | 81 | console.log(developer); 82 | // output: { firstname: 'robin', lastname: 'wieruch' } 83 | ~~~~~~~~ 84 | 85 | De plus, le nom d'import diffère du nom par défaut exporté. Vous pouvez aussi l'utiliser conjointement avec les exports nommés et les déclarations d'imports. 86 | 87 | {title="Code Playground: file1.js",lang="javascript"} 88 | ~~~~~~~~ 89 | const firstname = 'robin'; 90 | const lastname = 'wieruch'; 91 | 92 | const person = { 93 | firstname, 94 | lastname, 95 | }; 96 | 97 | export { 98 | firstname, 99 | lastname, 100 | }; 101 | 102 | export default person; 103 | ~~~~~~~~ 104 | 105 | Et importer l'export nommé ou par défaut dans un autre fichier. 106 | 107 | {title="Code Playground: file2.js",lang="javascript"} 108 | ~~~~~~~~ 109 | import developer, { firstname, lastname } from './file1.js'; 110 | 111 | console.log(developer); 112 | // output: { firstname: 'robin', lastname: 'wieruch' } 113 | console.log(firstname, lastname); 114 | // output: robin wieruch 115 | ~~~~~~~~ 116 | 117 | Vous pouvez aussi économiser des lignes additionnelles et exporter directement les variables en export nommé. 118 | 119 | {title="Code Playground: file1.js",lang="javascript"} 120 | ~~~~~~~~ 121 | export const firstname = 'robin'; 122 | export const lastname = 'wieruch'; 123 | ~~~~~~~~ 124 | 125 | Ce sont les principales fonctionnalités des modules ES6. Ils vous aide à organiser votre code, maintenir votre code et concevoir des APIs de module réutilisable. Vous pouvez aussi exporter et importer des fonctionnalités pour les tester. Vous ferez cela dans l'un des chapitres suivants. 126 | 127 | ### Exercices : 128 | 129 | * lire plus à propos [ES6 import](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) 130 | * lire plus à propos [ES6 export](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export) 131 | 132 | ## Organisation du code avec les modules ES6 133 | 134 | Vous pourriez vous demander : pourquoi nous n'avons pas suivi les meilleurs pratiques pour séparer notre code pour le fichier *src/App.js*? Dans le fichier nous avons déjà plusieurs composants qui pourrait être défini dans leurs propres (modules) fichiers/dossiers. Pour l'intérêt d'apprentissage de React, c'est pratique de conserver ces choses à un seul endroit. Mais une fois que votre application React grossit, vous devez considérer le fait de séparer ces composants à l'intérieur de plusieurs modules. La seule façon pour vos applications d'être mis à l'échelle. 135 | 136 | Par conséquent, je proposerai plusieurs structures de module que vous "pourriez" appliquer. Je vous recommande de les appliquer en tant qu'exercice à la fin du livre. Pour conserver le livre simple, j'effectuerai pas la séparation de code et continuerai les chapitres suivants avec le fichier *src/App.js*. 137 | 138 | Une structure de module possible serait : 139 | 140 | {title="Folder Structure",lang="text"} 141 | ~~~~~~~~ 142 | src/ 143 | index.js 144 | index.css 145 | App.js 146 | App.test.js 147 | App.css 148 | Button.js 149 | Button.test.js 150 | Button.css 151 | Table.js 152 | Table.test.js 153 | Table.css 154 | Search.js 155 | Search.test.js 156 | Search.css 157 | ~~~~~~~~ 158 | 159 | Cela sépare les composants à l'intérieur de leurs propres fichiers, mais cela ne semble pas très prometteur. Vous pouvez voir beaucoup de duplication de nom et seules les extensions de fichier diffèrent. Une autre structure de module serait : 160 | 161 | {title="Folder Structure",lang="text"} 162 | ~~~~~~~~ 163 | src/ 164 | index.js 165 | index.css 166 | App/ 167 | index.js 168 | test.js 169 | index.css 170 | Button/ 171 | index.js 172 | test.js 173 | index.css 174 | Table/ 175 | index.js 176 | test.js 177 | index.css 178 | Search/ 179 | index.js 180 | test.js 181 | index.css 182 | ~~~~~~~~ 183 | 184 | Cela semble plus propre qu'avant. La dénomination *index* d'un fichier le décrit comme étant le point d'entrée du dossier. C'est juste une convention de nommage commune, mais vous pouvez utiliser votre propre nommage également. Dans cette structure de module, un composant est défini par sa déclaration de composant dans le fichier JavaScript, mais aussi par son style et ses tests. 185 | 186 | Une autre étape pourrait être l'extraction des variables de constantes du composant App. Ces constantes étaient utilisées pour composer l'URL de l'API d'Hacker News. 187 | 188 | {title="Folder Structure",lang="text"} 189 | ~~~~~~~~ 190 | src/ 191 | index.js 192 | index.css 193 | # leanpub-start-insert 194 | constants/ 195 | index.js 196 | components/ 197 | # leanpub-end-insert 198 | App/ 199 | index.js 200 | test.js 201 | index.css 202 | Button/ 203 | index.js 204 | test.js 205 | index.css 206 | // ... 207 | ~~~~~~~~ 208 | 209 | Naturellement les modules devront être séparés à l'intérieur de *src/constants/* et *src/components/*. Maintenant le fichier *src/constants/index.js* pourrait ressembler à cela : 210 | 211 | {title="Code Playground: src/constants/index.js",lang="javascript"} 212 | ~~~~~~~~ 213 | export const DEFAULT_QUERY = 'redux'; 214 | export const DEFAULT_HPP = '100'; 215 | export const PATH_BASE = 'https://hn.algolia.com/api/v1'; 216 | export const PATH_SEARCH = '/search'; 217 | export const PARAM_SEARCH = 'query='; 218 | export const PARAM_PAGE = 'page='; 219 | export const PARAM_HPP = 'hitsPerPage='; 220 | ~~~~~~~~ 221 | 222 | Le fichier *App/index.js* peut importer ces variables pour les utiliser. 223 | 224 | {title="Code Playground: src/components/App/index.js",lang=javascript} 225 | ~~~~~~~~ 226 | import { 227 | DEFAULT_QUERY, 228 | DEFAULT_HPP, 229 | PATH_BASE, 230 | PATH_SEARCH, 231 | PARAM_SEARCH, 232 | PARAM_PAGE, 233 | PARAM_HPP, 234 | } from '../../constants/index.js'; 235 | 236 | // ... 237 | ~~~~~~~~ 238 | 239 | Lorsque vous utilisez la convention de nommage *index.js*, vous pouvez omettre le nom du fichier du chemin relatif. 240 | 241 | {title="Code Playground: src/components/App/index.js",lang=javascript} 242 | ~~~~~~~~ 243 | import { 244 | DEFAULT_QUERY, 245 | DEFAULT_HPP, 246 | PATH_BASE, 247 | PATH_SEARCH, 248 | PARAM_SEARCH, 249 | PARAM_PAGE, 250 | PARAM_HPP, 251 | # leanpub-start-insert 252 | } from '../../constants'; 253 | # leanpub-end-insert 254 | 255 | // ... 256 | ~~~~~~~~ 257 | 258 | Mais qu'est-ce qui est derrière le nommage de fichier *index.js*? La convention a été introduite dans le monde de node.js. Le fichier index est un point d'entrée auprès du module. Cela décrit l'API publique envers le module. Considérez la stucture de module suivante construite pour la démonstration : 259 | 260 | {title="Folder Structure",lang="text"} 261 | ~~~~~~~~ 262 | src/ 263 | index.js 264 | App/ 265 | index.js 266 | Buttons/ 267 | index.js 268 | SubmitButton.js 269 | SaveButton.js 270 | CancelButton.js 271 | ~~~~~~~~ 272 | 273 | Le dossier *Buttons/* a plusieurs composants boutons définis dans ses fichiers distincts. Chaque fichier peut `export default` un composant spécifique le rendant disponible pour *Buttons/index.js*. Le fichier *Buttons/index.js* importe tous les différentes représentation de bouton et les exporte en tant qu'API de module publique. 274 | 275 | {title="Code Playground: src/Buttons/index.js",lang="javascript"} 276 | ~~~~~~~~ 277 | import SubmitButton from './SubmitButton'; 278 | import SaveButton from './SaveButton'; 279 | import CancelButton from './CancelButton'; 280 | 281 | export { 282 | SubmitButton, 283 | SaveButton, 284 | CancelButton, 285 | }; 286 | ~~~~~~~~ 287 | 288 | Maintenant *src/App/index.js* peut importer les boutons à partir de l'API de module public localisé dans le fichier *index.js*. 289 | 290 | {title="Code Playground: src/App/index.js",lang=javascript} 291 | ~~~~~~~~ 292 | import { 293 | SubmitButton, 294 | SaveButton, 295 | CancelButton 296 | } from '../Buttons'; 297 | ~~~~~~~~ 298 | 299 | En suivant cette contrainte, il serait malvenu d'atteindre d'autres fichiers que l'*index.js* dans le module. Cela casserait les règles d'encapsulation. 300 | 301 | {title="Code Playground: src/App/index.js",lang=javascript} 302 | ~~~~~~~~ 303 | // Mauvaise pratique, ne faites pas çà 304 | import SubmitButton from '../Buttons/SubmitButton'; 305 | ~~~~~~~~ 306 | 307 | Maintenant vous savez comment vous pouvez refactorer votre code source dans des modules avec les contraintes d'encapsulation. Comme je l'ai dit, dans l'intérêt de garder le livre simple je n'appliquerai pas ces changements. mais vous devrez faire le refactoring lorsque vous avez terminé la lecture du livre. 308 | 309 | ### Exercices : 310 | 311 | * refactorer votre fichier *src/App.js* en plusieurs modules de composant lorsque vous avez terminé le livre 312 | 313 | ## Tests instantanés avec Jest 314 | 315 | Le livre ne plongera pas profondément à l'intérieur du sujet des tests, mais il ne doit pas être omis. Tester votre code en programmation est essentiel et doit être perçu comme obligatoire. Vous souhaitez conserver une bonne qualité de votre code et une assurance que tout fonctionne. 316 | 317 | Peut-être avez-vous entendu la pyramide de tests. Il y a les tests end-to-end, les tests d'intégration et les tests unitaires. Si vous n'êtes pas familier avec cela, le livre donne un rapide et basique aperçu. Un test unitaire est utilisé pour tester un bloc de code isolé et petit. Cela peut être une fonction seule qui est testée par un test unitaire. Cependant, parfois les tests unitaires fonctionnent en l'isolant mais ne fonctionnent plus en les combinant avec d'autres tests unitaires. Ils ont besoin d'être testés en tant que groupe de tests unitaires. C'est là où les tests d'intégration peuvent aider en couvrant le fait que les tests unitaires fonctionnent ensemble. Enfin, mais pas des moindres, un test end-to-end est la simulation d'un scénario utilisateur réel. Cela peut être une installation automatisée au sein du navigateur simulant les étapes d'authentification d'un utilisateur au sein d'une application web. Tandis que les tests unitaires sont rapides et faciles à écrire et maintenir, les tests end-to-end sont le total opposé. 318 | 319 | Combien de tests de chaque type ai-je besoin? Vous souhaitez avoir plusieurs tests unitaires pour couvrir vos fonctions isolées. Après quoi, vous pouvez avoir plusieurs tests d'intégration pour couvrir le fait que les fonctions les plus importantes fonctionnent de façons combinées comme attendues. Enfin, mais pas des moindres vous pourrez vouloir avoir seulement quelques tests end-to-end pour simuler les scénarios critiques de votre application web. C'est tout pour l'introdution générale au sein du monde des tests. 320 | 321 | Donc comment appliquer ces connaissances de tests pour votre application React? La base pour les tests au sein de React est les tests de composant qui peut être vulgarisé en tant que tests unitaires et une certaine partie en tant que tests instantanés. Vous mènerez les tests unitaires pour vos composants dans le prochain chapitre en utilisant une bibliothèque appelée Enzyme. Dans cette section du chapitre, vous vous concentrerez sur un autre type de tests : les tests d'instantanés. C'est là que Jest rentre en jeu. 322 | 323 | [Jest](https://jestjs.io/) est un framework JavaScript de tests qui est utilisé par Facebook. Dans la communauté React, c'est utilisé pour les tests de composant React. Heureusement *create-react-app* possède déjà Jest, donc vous n'avez pas besoin de vous préoccuper de son installation. 324 | 325 | Démarrons le test de vos premiers composants. Avant de pouvoir faire cela, vous devez exporter les composants, que vous allez tester, depuis votre fichier *src/App.js*. Après quoi vous pouvez les tester dans un fichier différent. Vous avez appris cela dans le chapitre portant sur l'organisation du code. 326 | 327 | {title="src/App.js",lang=javascript} 328 | ~~~~~~~~ 329 | // ... 330 | 331 | class App extends Component { 332 | // ... 333 | } 334 | 335 | // ... 336 | 337 | export default App; 338 | 339 | # leanpub-start-insert 340 | export { 341 | Button, 342 | Search, 343 | Table, 344 | }; 345 | # leanpub-end-insert 346 | ~~~~~~~~ 347 | 348 | Dans votre fichier *App.test.js*, vous trouverez un premier test qui a été constuit avec create-react-app*. Il vérifie que le composant App fera un rendu sans erreur. 349 | 350 | {title="src/App.test.js",lang=javascript} 351 | ~~~~~~~~ 352 | import React from 'react'; 353 | import ReactDOM from 'react-dom'; 354 | import App from './App'; 355 | 356 | it('renders without crashing', () => { 357 | const div = document.createElement('div'); 358 | ReactDOM.render(, div); 359 | ReactDOM.unmountComponentAtNode(div); 360 | }); 361 | ~~~~~~~~ 362 | 363 | Le block "it" décrit un cas de test. Il arrive avec une description de test et lorsque vous le testez, il peut soit réussir soit échouer. De plus, vous pouvez l'englober à l'intérieur d'un bloc "describe" qui définit votre suite de tests. Une suite de tests peut inclure un certain nombre de blocs "it" pour un composant spécifique. Vous verrez ces blocs "describe" après. Les deux blocs sont utilisés pour séparer et organiser vos cas de tests. 364 | 365 | Notez que la fonction `it` est connu dans la communauté JavaScript comme la fonction où vous lancez un test unique. Cependant, dans Jest c'est souvent perçu comme un alias de fonction `test`. 366 | 367 | Vous pouvez lancer vos cas de tests en utilisant le script de test interactif de *create-react-app* en ligne de commande. Vous obtiendrez la sortie pour tous les cas de tests sur votre interface en ligne de commande. 368 | 369 | {title="Command Line",lang="text"} 370 | ~~~~~~~~ 371 | npm test 372 | ~~~~~~~~ 373 | 374 | Maintenant Jest vous permet d'écrire des tests d'instantanés. Ces tests font un instantané de votre composant rendu et lancent cet instantané par rapport à de futurs instantanés. Lorsqu'un futurs intantané change, vous serez informé dans le test. Vous pouvez soit accepter le changement d'instantané, car vous avez changé l'implémentation du composant délibérément, ou rejeter le changement et investiguer sur l'erreur. Il complète les tests unitaires très bien, car vous testez seulement les différences sur la sortie rendue. Il n'ajoute pas un important coût de maintenance, car vous pouvez simplement accepter les instantanés modifiés lorsque vous changez quelques chose délibérément pour la sortie de rendu de votre composant. 375 | 376 | Jest stocke les instantanés dans un dossier. C'est seulement de cette façon qu'il peut valider la différence par rapport à un instantané futur. 377 | 378 | Avant l'écriture de votre premier test instantané avec Jest, vous devez installer une bibliothèque utilitaire. 379 | 380 | {title="Command Line",lang="text"} 381 | ~~~~~~~~ 382 | npm install --save-dev react-test-renderer 383 | ~~~~~~~~ 384 | 385 | Maintenant vous pouvez étendre le test du composant App avec votre premier test instantané. Premièrement, importer la nouvelle fonctionnalité depuis le node package et englober votre précédent bloc "it" du composant App dans un bloc de description "describe". Dans ce cas, la suite de test est consacré au composant App. 386 | 387 | {title="src/App.test.js",lang=javascript} 388 | ~~~~~~~~ 389 | import React from 'react'; 390 | import ReactDOM from 'react-dom'; 391 | # leanpub-start-insert 392 | import renderer from 'react-test-renderer'; 393 | # leanpub-end-insert 394 | import App from './App'; 395 | 396 | # leanpub-start-insert 397 | describe('App', () => { 398 | 399 | # leanpub-end-insert 400 | it('renders without crashing', () => { 401 | const div = document.createElement('div'); 402 | ReactDOM.render(, div); 403 | ReactDOM.unmountComponentAtNode(div); 404 | }); 405 | 406 | # leanpub-start-insert 407 | 408 | }); 409 | # leanpub-end-insert 410 | ~~~~~~~~ 411 | 412 | Maintenant vous pouvez implémenter votre premier instantané en utilisant un bloc "test". 413 | 414 | {title="src/App.test.js",lang=javascript} 415 | ~~~~~~~~ 416 | import React from 'react'; 417 | import ReactDOM from 'react-dom'; 418 | import renderer from 'react-test-renderer'; 419 | import App from './App'; 420 | 421 | describe('App', () => { 422 | 423 | it('renders without crashing', () => { 424 | const div = document.createElement('div'); 425 | ReactDOM.render(, div); 426 | ReactDOM.unmountComponentAtNode(div); 427 | }); 428 | 429 | # leanpub-start-insert 430 | test('has a valid snapshot', () => { 431 | const component = renderer.create( 432 | 433 | ); 434 | const tree = component.toJSON(); 435 | expect(tree).toMatchSnapshot(); 436 | }); 437 | # leanpub-end-insert 438 | 439 | }); 440 | ~~~~~~~~ 441 | 442 | Lancez de nouveau vos tests et observez comment les tests réussissent ou échouent. Ils devraient réussir. Une fois que vous modifiez la sortie du bloc de rendu de votre composant App, le test instantané doit échouer. Alors vous pouvez décider de mettre à jour l'instantané ou investiguer dans votre composant App. 443 | 444 | Globalement la fonction `renderer.create()` crée un instantané de votre composant App. Il le rend virtuellement et stocke le DOM à l'intérieur de l'instantané. Après quoi, l'instantané est attendu pour correspondre avec le précédent instantané au moment où vous avez lancé vos tests d'instantané. De cette façon, vous pouvez assurer que votre DOM reste le même et que rien ne change par accident. 445 | 446 | Ajoutons plus de tests pour nos composants indépendants. Premièrement, le composant Search : 447 | 448 | {title="src/App.test.js",lang=javascript} 449 | ~~~~~~~~ 450 | import React from 'react'; 451 | import ReactDOM from 'react-dom'; 452 | import renderer from 'react-test-renderer'; 453 | # leanpub-start-insert 454 | import App, { Search } from './App'; 455 | # leanpub-end-insert 456 | 457 | // ... 458 | 459 | # leanpub-start-insert 460 | describe('Search', () => { 461 | 462 | it('renders without crashing', () => { 463 | const div = document.createElement('div'); 464 | ReactDOM.render(Search, div); 465 | ReactDOM.unmountComponentAtNode(div); 466 | }); 467 | 468 | test('has a valid snapshot', () => { 469 | const component = renderer.create( 470 | Search 471 | ); 472 | const tree = component.toJSON(); 473 | expect(tree).toMatchSnapshot(); 474 | }); 475 | 476 | }); 477 | 478 | # leanpub-end-insert 479 | ~~~~~~~~ 480 | 481 | Le composant Search a deux tests similaires au composant App. Le premier test rend simplement le composant Search auprès du DOM et vérifie qu'il n'y est pas d'erreur durant le processus de rendu. S'il y aurait une erreur, le test casserait même s'il n'y a pas d'assertion. (ex : expect, match, equal) dans le bloc de test. Le second test d'instantané est utilisé pour stocker un instantané du composant rendu et de le lancer par rapport au précédent instantané. Il échoue lorsque l'instantané a changé. 482 | 483 | Deuxièmement, vous pouvez tester le composant Button auquel les mêmes principes de tests que le composant Search sont appliqués. 484 | 485 | {title="src/App.test.js",lang=javascript} 486 | ~~~~~~~~ 487 | // ... 488 | # leanpub-start-insert 489 | import App, { Search, Button } from './App'; 490 | # leanpub-end-insert 491 | 492 | // ... 493 | 494 | # leanpub-start-insert 495 | describe('Button', () => { 496 | 497 | it('renders without crashing', () => { 498 | const div = document.createElement('div'); 499 | ReactDOM.render(, div); 500 | ReactDOM.unmountComponentAtNode(div); 501 | }); 502 | 503 | test('has a valid snapshot', () => { 504 | const component = renderer.create( 505 | 506 | ); 507 | const tree = component.toJSON(); 508 | expect(tree).toMatchSnapshot(); 509 | }); 510 | 511 | }); 512 | # leanpub-end-insert 513 | ~~~~~~~~ 514 | 515 | Enfin, mais pas des moindres, le composant Table auquel vous pouvez passer un ensemble de `props` initiales dans le but de le rendre avec un échantillon de liste. 516 | 517 | {title="src/App.test.js",lang=javascript} 518 | ~~~~~~~~ 519 | // ... 520 | # leanpub-start-insert 521 | import App, { Search, Button, Table } from './App'; 522 | # leanpub-end-insert 523 | 524 | // ... 525 | 526 | # leanpub-start-insert 527 | describe('Table', () => { 528 | 529 | const props = { 530 | list: [ 531 | { title: '1', author: '1', num_comments: 1, points: 2, objectID: 'y' }, 532 | { title: '2', author: '2', num_comments: 1, points: 2, objectID: 'z' }, 533 | ], 534 | }; 535 | 536 | it('renders without crashing', () => { 537 | const div = document.createElement('div'); 538 | ReactDOM.render(, div); 539 | }); 540 | 541 | test('has a valid snapshot', () => { 542 | const component = renderer.create( 543 |
544 | ); 545 | const tree = component.toJSON(); 546 | expect(tree).toMatchSnapshot(); 547 | }); 548 | 549 | }); 550 | # leanpub-end-insert 551 | ~~~~~~~~ 552 | 553 | Les tests d'instantané habituellement restent assez basiques. Vous voulez seulement couvrir le fait que le composant ne change pas sa sortie. Une fois qu'il change la sortie, vous devez décider si vous acceptez les changements. Autrement vous devez réparer le composant lorsque la sortie n'est pas une sortie désirée. 554 | 555 | ### Exercices : 556 | 557 | * regarder comment un test d'instantané échoue une fois que vous changez votre valeur de retour du composant avec la méthode `render()` 558 | * acceptez ou rejetez le changement d'instantané 559 | * conservez vos instantanés à jour lorsque l'implémentation de composant change dans les prochains chapitres 560 | * lire plus à propos de [Jest au sein de React](https://jestjs.io/docs/en/tutorial-react) 561 | 562 | ## Les tests unitaires avec Enzyme 563 | 564 | [Enzyme](https://github.com/airbnb/enzyme) est un utilitaire de test d'Airbnb pour assert, manipuler et traverser vos composants React. Vous pouvez l'utiliser pour piloter vos tests unitaires dans le but de compléter vos tests d'instantanés dans React. 565 | 566 | Regardons comment vous pouvez utiliser Enzyme. Premièrement vous devez l'installer puisqu'il n'est pas embarqué dans *create-react-app*. Il arrive avec une extension pour l'utiliser au sein de React. 567 | 568 | {title="Command Line",lang="text"} 569 | ~~~~~~~~ 570 | npm install --save-dev enzyme react-addons-test-utils enzyme-adapter-react-16 571 | ~~~~~~~~ 572 | 573 | Deuxièmement, vous aurez besoin de l'inclure dans votre installation de test et initialiser son Adapter pour son usage au sein de React. 574 | 575 | {title="src/App.test.js",lang=javascript} 576 | ~~~~~~~~ 577 | import React from 'react'; 578 | import ReactDOM from 'react-dom'; 579 | import renderer from 'react-test-renderer'; 580 | # leanpub-start-insert 581 | import Enzyme from 'enzyme'; 582 | import Adapter from 'enzyme-adapter-react-16'; 583 | # leanpub-end-insert 584 | import App, { Search, Button, Table } from './App'; 585 | 586 | # leanpub-start-insert 587 | Enzyme.configure({ adapter: new Adapter() }); 588 | # leanpub-end-insert 589 | ~~~~~~~~ 590 | 591 | Maintenant, vous pouvez écrire votre premier test unitaire dans le bloc "description" de Table. Vous utiliserez `shallow()` pour rendre votre composant et affirmer que la Table possède deux objets, car vous lui passez deux éléments de liste. L'affirmation vérifie simplement si l'élément possède deux éléments avec la classe `table-row`. 592 | 593 | {title="src/App.test.js",lang=javascript} 594 | ~~~~~~~~ 595 | import React from 'react'; 596 | import ReactDOM from 'react-dom'; 597 | import renderer from 'react-test-renderer'; 598 | # leanpub-start-insert 599 | import Enzyme, { shallow } from 'enzyme'; 600 | # leanpub-end-insert 601 | import Adapter from 'enzyme-adapter-react-16'; 602 | import App, { Search, Button, Table } from './App'; 603 | 604 | // ... 605 | 606 | describe('Table', () => { 607 | 608 | const props = { 609 | list: [ 610 | { title: '1', author: '1', num_comments: 1, points: 2, objectID: 'y' }, 611 | { title: '2', author: '2', num_comments: 1, points: 2, objectID: 'z' }, 612 | ], 613 | }; 614 | 615 | // ... 616 | 617 | # leanpub-start-insert 618 | it('shows two items in list', () => { 619 | const element = shallow( 620 |
621 | ); 622 | 623 | expect(element.find('.table-row').length).toBe(2); 624 | }); 625 | # leanpub-end-insert 626 | 627 | }); 628 | ~~~~~~~~ 629 | 630 | *Shallow* rend le composant sans ses composants enfants. De cette façon, vous pouvez faire le test dévoué à un seul composant. 631 | 632 | Enzyme a dans l'ensemble trois mécanismes de rendu dans son API? Vous connaissez déjà `shallow()`, mais il y existe aussi `mount()` and `render()`. Les deux instancient les instances du composant parent ainsi que tous les composants enfants. De plus `mount()` vous donne un accès aux méthodes de cycle de vie du composant. Mais quand savoir utiliser quel mécanisme de rendu? Ici quelques règles générales : 633 | 634 | * Toujours débuter avec un test shallow 635 | * Si `componentDidMount()` ou `componentDidUpdate()` doit être testé, utiliser `mount()` 636 | * Si vous voulez tester le cycle de vie du composant et le comportement des enfants, utiliser `mount()` 637 | * Si vous voulez tester un rendu des enfants du composant avec moins de contrainte que `mount()` et que vous n'êtes pas intéressé par les méthodes du cycle de vie, utilisez `render()` 638 | 639 | Vous pouvez continuer à tester unitairement vos composants. Mais assurez-vous de conserver les tests simple et maintenable. Autrement vous devrez les refactorer une fois que vous modifiez vos composants. C'est pourquoi Facebook a introduit les tests instantanés avec Jest en premier lieu. 640 | 641 | ### Exercices : 642 | 643 | * écrire un test unitaire avec Enzyme pour votre composant Button 644 | * conserver vos tests unitaires à jour durant le chapitre suivant 645 | * lire plus à propos d'[Enzyme et de son API de rendu](https://github.com/airbnb/enzyme) 646 | * lire plus à propos du [testing des applications React](https://www.robinwieruch.de/react-testing-tutorial) 647 | 648 | ## Interface de composant avec les PropTypes 649 | 650 | Vous pourriez connaitre [TypeScript](https://www.typescriptlang.org/) ou [Flow](https://flowtype.org/) pour introduire une interface de type pour JavaScript. Un langage typé est plus robuste aux errors, car le code sera validé en fonction de son propre code. Les éditeurs et autres utilitaires peuvent saisir ces erreurs avant que le programme soit lancé. Cela rend votre programme plus robuste. 651 | 652 | Dans le livre, vous ne serez pas introduit à Flow ou TypeScript, mais à une autre façon proche de tester vos types dans les composants. React arrive avec un vérificateur de type embarqué pour empêcher les bugs. Vous pouvez utiliser *PropTypes* pour décrire votre interface de composant. Toutes les propriétés qui sont passées depuis un composant parent à un composant enfant seront validées selon l'interface *PropTypes* assignée au composant enfant. 653 | 654 | Cette section du chapitre vous montera comment vous pouvez rendre tous vos types de composants sûrs avec *PropTypes*. J'omettrai ces changements pour les prochains chapitres, car ils ajoutent du remaniement de code inutile. Mais vous pouvez les conserver et les mettre à jour tout du long pour conserver votre type d'interface de composants sûrs. 655 | 656 | Premièrement, vous devez installer un package séparé pour React. 657 | 658 | {title="Command Line",lang="text"} 659 | ~~~~~~~~ 660 | npm install prop-types 661 | ~~~~~~~~ 662 | 663 | Maintenant, vous pouvez importer *les PropTypes*. 664 | 665 | {title="src/App.js",lang=javascript} 666 | ~~~~~~~~ 667 | import React, { Component } from 'react'; 668 | import axios from 'axios'; 669 | # leanpub-start-insert 670 | import PropTypes from 'prop-types'; 671 | # leanpub-end-insert 672 | ~~~~~~~~ 673 | 674 | Débutons en assignant une interface de propriétés aux composants : 675 | 676 | {title="src/App.js",lang=javascript} 677 | ~~~~~~~~ 678 | const Button = ({ 679 | onClick, 680 | className = '', 681 | children, 682 | }) => 683 | 690 | 691 | # leanpub-start-insert 692 | Button.propTypes = { 693 | onClick: PropTypes.func, 694 | className: PropTypes.string, 695 | children: PropTypes.node, 696 | }; 697 | # leanpub-end-insert 698 | ~~~~~~~~ 699 | 700 | Tout simplement. Vous prenez chaque argument depuis la signature de fonction et lui assigner un *PropType*. Le *PropTypes* basiques pour les primitives et les objets complexes sont : 701 | 702 | * PropTypes.array 703 | * PropTypes.bool 704 | * PropTypes.func 705 | * PropTypes.number 706 | * PropTypes.object 707 | * PropTypes.string 708 | 709 | De plus vous avez deux PropTypes supplémentaires pour définir un fragment (node) présentable, ex : une string, et un élément React : 710 | 711 | * PropTypes.node 712 | * PropTypes.element 713 | 714 | Vous utilisez déjà le *PropType* `node` pour le composant Button. Globalement il y a des définitions de *PropType* supplémentaires que vous pouvez étudier dans la documentation officielle de React. 715 | 716 | Pour le moment tout les *PropTypes* définies pour le Button sont optionnelles. Les paramètres peuvent être `null` ou `undefined`. Mais pour certaines propriétés vous voudriez imposer le fait qu'elles soient définies. Vous pouvez rendre nécessaire le fait que ces propriétés sont passées au composant. 717 | 718 | {title="src/App.js",lang=javascript} 719 | ~~~~~~~~ 720 | Button.propTypes = { 721 | # leanpub-start-insert 722 | onClick: PropTypes.func.isRequired, 723 | # leanpub-end-insert 724 | className: PropTypes.string, 725 | # leanpub-start-insert 726 | children: PropTypes.node.isRequired, 727 | # leanpub-end-insert 728 | }; 729 | ~~~~~~~~ 730 | 731 | La `className` n'est pas requise, car elle peut par défaut être une chaine de caractère vide. Après vous définirez une interface *PropTypes* pour le composant Table : 732 | 733 | {title="src/App.js",lang=javascript} 734 | ~~~~~~~~ 735 | # leanpub-start-insert 736 | Table.propTypes = { 737 | list: PropTypes.array.isRequired, 738 | onDismiss: PropTypes.func.isRequired, 739 | }; 740 | # leanpub-end-insert 741 | ~~~~~~~~ 742 | 743 | Vous pouvez définir le contenu d'un *PropType* tableau plus explicitement : 744 | 745 | {title="src/App.js",lang=javascript} 746 | ~~~~~~~~ 747 | Table.propTypes = { 748 | list: PropTypes.arrayOf( 749 | PropTypes.shape({ 750 | objectID: PropTypes.string.isRequired, 751 | author: PropTypes.string, 752 | url: PropTypes.string, 753 | num_comments: PropTypes.number, 754 | points: PropTypes.number, 755 | }) 756 | ).isRequired, 757 | onDismiss: PropTypes.func.isRequired, 758 | }; 759 | ~~~~~~~~ 760 | 761 | Seul l'`objectID` est requis, car vous savez que certaines parties de votre code en dépendent. Les autres propriétés sont seulement affichées, ainsi elles ne sont pas nécessairement requises. De plus vous ne pouvez être sûr que l'API d'Hacker News a toujours une propriété définie pour chaque objet dans le tableau. 762 | 763 | C'est tout pour les *PropTypes*. Mais il y a un autre aspect. Vous pouvez définir des propriétés par défaut dans votre composant. Prenons de nouveau le composant Button. La propriété `className` a un paramètre ES6 par défaut dans la signature du composant. 764 | 765 | {title="src/App.js",lang=javascript} 766 | ~~~~~~~~ 767 | const Button = ({ 768 | onClick, 769 | className = '', 770 | children 771 | }) => 772 | // ... 773 | ~~~~~~~~ 774 | 775 | Vous pouvez le remplacer avec la propriété par défaut interne de React : 776 | 777 | {title="src/App.js",lang=javascript} 778 | ~~~~~~~~ 779 | # leanpub-start-insert 780 | const Button = ({ 781 | onClick, 782 | className, 783 | children 784 | }) => 785 | # leanpub-end-insert 786 | 793 | 794 | # leanpub-start-insert 795 | Button.defaultProps = { 796 | className: '', 797 | }; 798 | # leanpub-end-insert 799 | ~~~~~~~~ 800 | 801 | Identique que le paramètre par défaut d'ES6, la propriété par défaut assure que la propriété est établie à une valeur par défaut lorsque le composant parent n'est pas spécifié. La vérification du type de *PropType* se produit après que la propriété par défaut est évaluée. 802 | 803 | Si vous lancez de nouveau vos tests, vous pourriez voir les erreurs *PropTypes* de vos composants dans votre terminal. Elles peuvent apparaitre car vous n'avez pas défini toutes les propriétés de vos composants dans les tests qui sont définis comme requises dans votre définition de *PropType*. Cependant les tests eux-même passent correctement. Vous pouvez passer toutes les propriétés requises aux composants dans vos tests pour éviter ces erreurs. 804 | 805 | ### Exercices : 806 | 807 | * définir l'interface *PropType* pour le composant Search 808 | * ajouter et mettre à jour les interfaces *PropType* lorsque vous ajoutez et mettez à jour des composants dans les prochains chapitres 809 | * lire plus à propos des [PropTypes de React](https://reactjs.org/docs/typechecking-with-proptypes.html) 810 | 811 | ## Débuggage à l'aide du React Developer Tools 812 | 813 | Cette dernière section vous présente un outil très utile, généralement utilisé pour inspecter et debugger les applications React. [React Developer Tools](https://github.com/facebook/react-devtools) vous laisse inspecter la hiérarchie des composants React, les props et l'état. C'est une extension de navigateur web (pour l'heure, sur Chrome et Firefox) et une application standalone (qui fonctionne sur d'autres environnements). 814 | 815 | Une fois installé, l'icône de l'extension s'éclairera sur les sites web utilisant React. Sur ces sites web, vous verrez un onglet appelé "React" au sein de votre browser developer tools. 816 | 817 | Essayons cela sur notre application Hacker News. Sur la plupart des navigateurs, un moyen rapide pour faire apparaître le _dev tools_ up consiste à réaliser un click droit sur la page et allez sur “Inspecter”. Faites-le lorsque votre application est chargée, puis cliquez sur l'onglet "React". Vous devriez voir sa hiérarchie d'éléments, avec `` l'élément racine. Si vous le développez, vous trouverez également des instances de vos composants ``, `
` et ` 42 | 43 | # leanpub-start-insert 44 | ); 45 | } 46 | } 47 | # leanpub-end-insert 48 | ~~~~~~~~ 49 | 50 | L'objet `this` du composant de classe ES6 nous aide à référencer l'élément du DOM avec l'attribut `ref`. 51 | 52 | {title="src/App.js",lang=javascript} 53 | ~~~~~~~~ 54 | class Search extends Component { 55 | render() { 56 | const { 57 | value, 58 | onChange, 59 | onSubmit, 60 | children 61 | } = this.props; 62 | 63 | return ( 64 | 65 | this.input = el} 71 | # leanpub-end-insert 72 | /> 73 | 76 | 77 | ); 78 | } 79 | } 80 | ~~~~~~~~ 81 | 82 | Maintenant vous pouvez focus le champ d'entrée lorsque le composant est monté en utilisant l'objet `this`, la méthode du cycle de vie appropriée, et l'API du DOM. 83 | 84 | {title="src/App.js",lang=javascript} 85 | ~~~~~~~~ 86 | class Search extends Component { 87 | # leanpub-start-insert 88 | componentDidMount() { 89 | if (this.input) { 90 | this.input.focus(); 91 | } 92 | } 93 | # leanpub-end-insert 94 | 95 | render() { 96 | const { 97 | value, 98 | onChange, 99 | onSubmit, 100 | children 101 | } = this.props; 102 | 103 | return ( 104 | 105 | this.input = el} 110 | /> 111 | 114 | 115 | ); 116 | } 117 | } 118 | ~~~~~~~~ 119 | 120 | Le champ d'entrée doit être focus lorsque l'application se rend. C'est essentiellement tout pour l'usage de l'attribut `ref`. 121 | 122 | Mais comment vous aurez accès au `ref` dans un composant fonctionnel stateless sans l'objet `this`? Le composant fonctionnel stateless suivant en fait une démonstration : 123 | 124 | {title="src/App.js",lang=javascript} 125 | ~~~~~~~~ 126 | const Search = ({ 127 | value, 128 | onChange, 129 | onSubmit, 130 | children 131 | }) => { 132 | # leanpub-start-insert 133 | let input; 134 | # leanpub-end-insert 135 | return ( 136 | 137 | this.input = el} 143 | # leanpub-end-insert 144 | /> 145 | 148 | 149 | ); 150 | } 151 | ~~~~~~~~ 152 | 153 | Maintenant vous serez capable d'accéder à l'entrée de l'élément du DOM. Dans l'exemple de la fonctionnalité du focus cela ne vous aidera pas, car vous ne disposez pas des méthodes du cycle de vie dans un composant fonctionnel stateless pour déclencher le focus. Mais dans un futur vous pourrez traverser d'autres cas d'utilisation où il y aura du sens d'utiliser un composant fonctionnel stateless avec l'attribut `ref`. 154 | 155 | ### Exercises 156 | 157 | * lire plus à propos de l'[usage de l'attribut ref au sein de React](https://www.robinwieruch.de/react-ref-attribute-dom-node/) 158 | * lire plus à propos de l'[attribut ref de façon générale au sein de React](ttps://reactjs.org/docs/refs-and-the-dom.html) 159 | 160 | ## Chargement ... 161 | 162 | Retournons à l'application. Vous pourriez vouloir afficher un indicateur de chargement lorsque vous soumettez une requête de recherche à l'API d'Hacker News. La requête est asynchrone et vous devrez montrer à votre utilisateur quelques retours visuels que quelque chose se produit. Définissons un composant Loading réutilisable dans votre fichier *src/App.js*. 163 | 164 | {title="src/App.js",lang=javascript} 165 | ~~~~~~~~ 166 | const Loading = () => 167 |
Loading ...
168 | ~~~~~~~~ 169 | 170 | Maintenant vous aurez besoin d'une propriété pour stocker l'état du chargement. Selon l'état du chargement vous pouvez décider de montrer le composant Loading par la suite. 171 | 172 | {title="src/App.js",lang=javascript} 173 | ~~~~~~~~ 174 | class App extends Component { 175 | _isMounted = false; 176 | 177 | constructor(props) { 178 | super(props); 179 | 180 | this.state = { 181 | results: null, 182 | searchKey: '', 183 | searchTerm: DEFAULT_QUERY, 184 | error: null, 185 | # leanpub-start-insert 186 | isLoading: false, 187 | # leanpub-end-insert 188 | }; 189 | 190 | // ... 191 | } 192 | 193 | // ... 194 | 195 | } 196 | ~~~~~~~~ 197 | 198 | La valeur initiale de votre propriété `isLoading` est fausse. Vous ne chargez rien avant que le composant App soit monté. 199 | 200 | Lorsque vous faites la requête, vous mutez l'état de chargement à true. Finalement la requête réussira et vous pourrez muter l'état de chargement à false. 201 | 202 | {title="src/App.js",lang=javascript} 203 | ~~~~~~~~ 204 | class App extends Component { 205 | 206 | // ... 207 | 208 | setSearchTopStories(result) { 209 | // ... 210 | 211 | this.setState({ 212 | results: { 213 | ...results, 214 | [searchKey]: { hits: updatedHits, page } 215 | }, 216 | # leanpub-start-insert 217 | isLoading: false 218 | # leanpub-end-insert 219 | }); 220 | } 221 | 222 | fetchSearchTopStories(searchTerm, page = 0) { 223 | # leanpub-start-insert 224 | this.setState({ isLoading: true }); 225 | # leanpub-end-insert 226 | 227 | axios(`${PATH_BASE}${PATH_SEARCH}?${PARAM_SEARCH}${searchTerm}&${PARAM_PAGE}${page}&${PARAM_HPP}${DEFAULT_HPP}`) 228 | .then(result => this._isMounted && this.setSearchTopStories(result.data)) 229 | .catch(error => this._isMounted && this.setState({ error })); 230 | } 231 | 232 | // ... 233 | 234 | } 235 | ~~~~~~~~ 236 | 237 | Dernière étape, vous utiliserez le composant Loading dans votre App. Un rendu conditionnel basé sur l'état de chargement décidera si vous affichez le composant Loading ou le composant Button. Ce dernier est votre bouton pour aller chercher plus de données. 238 | 239 | {title="src/App.js",lang=javascript} 240 | ~~~~~~~~ 241 | class App extends Component { 242 | 243 | ... 244 | 245 | render() { 246 | const { 247 | searchTerm, 248 | results, 249 | searchKey, 250 | error, 251 | # leanpub-start-insert 252 | isLoading 253 | # leanpub-end-insert 254 | } = this.state; 255 | 256 | // ... 257 | 258 | return ( 259 |
260 | // ... 261 |
262 | # leanpub-start-insert 263 | { isLoading 264 | ? 265 | : 269 | } 270 | # leanpub-end-insert 271 |
272 |
273 | ); 274 | } 275 | } 276 | ~~~~~~~~ 277 | 278 | Initialement le composant Loading s'affichera lorsque vous démarrer votre application, car vous ferez une requête avec `componentDidMount()`. Il n'y a pas de composant Table, car le liste est vide. Lorsque la réponse revient de l'API d'Hacker News, le résultat est montré, le chargement d'état est muté à false et le composant Loading disparaît. À la place, le bouton "More" pour aller chercher plus de données apparaît. Une fois que vous recherchez plus de données, le bouton disparaîtra de nouveau et le composant Loading se révèlera. 279 | 280 | ### Exercices : 281 | 282 | * utiliser une biblohtèque telle que [Font Awesome](https://fontawesome.io/) pour afficher une icône de chargement au lieu du texte "Loading ..." 283 | 284 | ## Composants d'ordre supérieur 285 | 286 | Les composants d'ordre supérieur (HOC) sont un concept avancé en React. Les HOCs sont un équivalent des fonctions d'ordre supérieur. Ils prennent plusieurs entrées - la plupart du temps un composant, mais aussi des arguments optionnels - et retournent un composant en sortie. Le composant retourné est une version améliorée du composant d'entrée et peut-être utilisé dans votre JSX. 287 | 288 | Les HOCs sont utilisés pour différents cas d'utilisation. Ils préparent les propriétés, gère l'état où altère la représentation d'un composant. Un cas d'utilisation pourrait être d'utiliser un HOC en tant qu'assistant pour un rendu conditionnel. Imaginez-vous avez un composant List qui rend une liste d'éléments ou rien, car la liste est vide ou null. L'HOC pourrait protéger le fait que la liste souhaiterait ne rien rendre lorsqu'il n'y a pas de liste. À l'inverse, le sobre composant List n'a plus besoin de s'encombrer d'une liste non existante. Il se préoccupe seulement de la liste rendue. 289 | 290 | Faisons un simple HOC qui prend un composant en entrée et retourne un composant. Vous pouvez le placer à l'intérieur de votre fichier *src/App.js*. 291 | 292 | {title="src/App.js",lang=javascript} 293 | ~~~~~~~~ 294 | function withFoo(Component) { 295 | return function(props) { 296 | return ; 297 | } 298 | } 299 | ~~~~~~~~ 300 | 301 | Une convention cohérente est de préfixer le nommage d'HOC avec `with`. Puisque vous utilisez du JavaScript ES6, vous pouvez exprimer l'HOC plus concisément avec une fonction fléchée ES6. 302 | 303 | {title="src/App.js",lang=javascript} 304 | ~~~~~~~~ 305 | const withFoo = (Component) => (props) => 306 | 307 | ~~~~~~~~ 308 | 309 | Dans l'exemple, le composant d'entrée devrait rester le même que le composant de sortie. Rien ne se produit. Il rend la même instance de composant et passe toutes les propriétés au composant de sortie. Mais c'est inutile. Améliorons le composant de sortie. Le composant de sortie devrait afficher le composant Loading, quand l'état de chargement est à true, autrement il devrait afficher le composant d'entrée. Un rendu conditionnel est un bon cas d'utilisation pour un HOC. 310 | 311 | {title="src/App.js",lang=javascript} 312 | ~~~~~~~~ 313 | # leanpub-start-insert 314 | const withLoading = (Component) => (props) => 315 | props.isLoading 316 | ? 317 | : 318 | # leanpub-end-insert 319 | ~~~~~~~~ 320 | 321 | Basé sur la propriété de chargement vous pouvez appliquer un rendu conditionnel. La fonction retournera le composant de chargement ou le composant d'entrée. 322 | 323 | En général il peut être efficace de diffuser un objet, tel que les propriétés d'objet dans l'exemple précédent, en tant qu'entrée pour un composant. Observez la différence avec le bout de code suivant. 324 | 325 | {title="Code Playground",lang="javascript"} 326 | ~~~~~~~~ 327 | // avant vous aurez déstructuré les propriétés avant de les transmettre 328 | const { foo, bar } = props; 329 | 330 | 331 | // Mais vous pouvez utiliser le spread operator objet pour transmettre toutes les propriétés de l'objet. 332 | 333 | ~~~~~~~~ 334 | 335 | Il y a une petite chose que vous devez éviter. Vous passez toutes les propriétés incluant la propriété `isLoading`, en diffusant l'objet, à l'intérieur du composant d'entrée. Cependant, le composant d'entrée pourrait ne pas désirer la propriété `isLoading`. Vous pouvez utiliser la décomposition du reste en ES6 pour éviter cela. 336 | 337 | {title="src/App.js",lang=javascript} 338 | ~~~~~~~~ 339 | # leanpub-start-insert 340 | const withLoading = (Component) => ({ isLoading, ...rest }) => 341 | isLoading 342 | ? 343 | : 344 | # leanpub-end-insert 345 | ~~~~~~~~ 346 | 347 | Cela prend une propriété à l'extérieur de l'objet, mais conserve le reste de l'objet. Cela fonctionne avec plusieurs propriétés également. Vous pourriez l'avoir déjà lu dans l'[affectation par décomposition](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment). 348 | 349 | Maintenant vous pouvez utiliser l'HOC dans votre JSX. Un cas d'utilisation au sein de l'application pourrait être d'afficher soit le bouton "More" soit le composant Loading. Le composant Loading est toujours encapsulé dans l'HOC, mais un composant en entrée est manquant. Dans le cas d'utilisation consistant à montrer un composant Button ou un composant Loading, le Button est le composant d'entrée de l'HOC. Le composant de sortie améliorée est un composant ButtonWithLoading. 350 | 351 | {title="src/App.js",lang=javascript} 352 | ~~~~~~~~ 353 | const Button = ({ 354 | onClick, 355 | className = '', 356 | children, 357 | }) => 358 | 365 | 366 | const Loading = () => 367 |
Loading ...
368 | 369 | const withLoading = (Component) => ({ isLoading, ...rest }) => 370 | isLoading 371 | ? 372 | : 373 | 374 | # leanpub-start-insert 375 | const ButtonWithLoading = withLoading(Button); 376 | # leanpub-end-insert 377 | ~~~~~~~~ 378 | 379 | Maintenant tout est défini. En dernier étape, vous devez utiliser le composant ButtonWithLoading, qui reçoit l'état de chargement en tant que propriété additionnelle. Tandis que l'HOC consomme la propriété loading, tout autres propriétés seront transmises au composant Button. 380 | 381 | {title="src/App.js",lang=javascript} 382 | ~~~~~~~~ 383 | class App extends Component { 384 | 385 | // ... 386 | 387 | render() { 388 | // ... 389 | return ( 390 |
391 | // ... 392 |
393 | # leanpub-start-insert 394 | this.fetchSearchTopStories(searchKey, page + 1)}> 397 | More 398 | 399 | # leanpub-end-insert 400 |
401 |
402 | ); 403 | } 404 | } 405 | ~~~~~~~~ 406 | 407 | Lorsque vous lancez de nouveau vos tests, vous remarquerez que votre test d'instantané pour le composant App échoue. La différence devrait ressembler à cela sur le terminal : 408 | 409 | {title="Command Line",lang="text"} 410 | ~~~~~~~~ 411 | - 418 | +
419 | + Loading ... 420 | +
421 | ~~~~~~~~ 422 | 423 | Vous pouvez maintenant soit réparer le composant, lorsque vous pensez qu'il y a quelques soucis avec cela, ou vous pouvez accepter le nouvel instantané. Parceque vous avez introduit le composant Loading dans ce chapitre, vous pouvez accepter la version modifiée du test d'instantané sur le terminal dans le test interactif. 424 | 425 | Les composants d'ordre supérieur sont une technique avancée dans React. Ils ont de multiples buts comme améliorer la réutilisabilité des composants, une meilleure abstraction, une composabilité des composants et la manipulation des propriétés ainsi que de l'état et la vue. Ne vous inquiétez pas si vous ne les comprenez pas immédiatement. Cela prend du temps à s'habituer à eux. 426 | 427 | Je vous encourage à lire la [véritable introduction aux composants d'ordre supérieur](https://www.robinwieruch.de/gentle-introduction-higher-order-components/). Il vous fournit une autre approche pour les apprendre, vous montre une façon élégante de les utiliser dans une approche de programmation fonctionnelle et résout spécifiquement le problème de rendu conditionnel avec les composants d'ordre supérieur. 428 | 429 | ### Exercices : 430 | 431 | * lire la [véritable introduction aux composants d'ordre supérieur](https://www.robinwieruch.de/gentle-introduction-higher-order-components/) 432 | * experimenter avec l'HOC que vous avez créé 433 | * penser à un cas d'utilisation où un autre HOC ferait sens 434 | * implementer l'HOC, s'l y a un cas d'utilisation 435 | 436 | ## Tri avancé 437 | 438 | Vous avez déjà implémenté une interaction de recherche côté client et serveur. Puisque vous avez un composant Table, il ferait sens d'améliorer le Table avec des interactions avancées. Pourquoi ne pas introduire une fonctionnalité de tri pour chaque colonne en utilisant les en-têtes de colonnes du Table? 439 | 440 | Il serait possible d'écrire votre propre fonction `sort`, mais personnellement je préfère utiliser une bibliothèque pour ce genre de cas. [Lodash](https://lodash.com/) est l'une de ces bibliothèques utiles, mais vous pouvez utiliser n'importe quelle bibliothèque qui vous correspond. Installons Lodash et utilisons la pour la fonctionnalité de tri. 441 | 442 | {title="Command Line",lang="text"} 443 | ~~~~~~~~ 444 | npm install lodash 445 | ~~~~~~~~ 446 | 447 | Maintenant vous pouvez importer la fonctionnalité de tri de Lodash dans votre fichier *src/App.js*. 448 | 449 | {title="src/App.js",lang=javascript} 450 | ~~~~~~~~ 451 | import React, { Component } from 'react'; 452 | import axios from 'axios'; 453 | # leanpub-start-insert 454 | import { sortBy } from 'lodash'; 455 | # leanpub-end-insert 456 | import './App.css'; 457 | ~~~~~~~~ 458 | 459 | Vous avez plusieurs colonnes dans votre Table. Il y a les colonnes title, author, comments et points. Vous pouvez définir les fonctions de tri ainsi chaque fonction prend une liste et retourne une liste d'éléments triée en spécifiant la propriété. Qui plus est, vous aurez besoin d'une fonction de tri par défaut qui ne triera pas mais seulement retournera la liste non triée. Cela sera votre état initial. 460 | 461 | {title="src/App.js",lang=javascript} 462 | ~~~~~~~~ 463 | // ... 464 | 465 | # leanpub-start-insert 466 | const SORTS = { 467 | NONE: list => list, 468 | TITLE: list => sortBy(list, 'title'), 469 | AUTHOR: list => sortBy(list, 'author'), 470 | COMMENTS: list => sortBy(list, 'num_comments').reverse(), 471 | POINTS: list => sortBy(list, 'points').reverse(), 472 | }; 473 | # leanpub-end-insert 474 | 475 | class App extends Component { 476 | // ... 477 | } 478 | // ... 479 | ~~~~~~~~ 480 | 481 | Vous pouvez voir qu'il y a deux fonctions de tri qui retournent une liste inversée. C'est parce que vous voulez voir les éléments avec le plus de commentaires et de points plutôt que de voir les éléments avec le total le plus faible lorsque vous triez la liste pour la première fois. 482 | 483 | Maintenant l'objet `SORTS` vous permet de référencer toutes fonctions de tri. 484 | 485 | Encore une fois votre composant App est responsable de stocker l'état du tri. L'état initial sera la fonction de tri initial par défaut, qui trie pas du tout mais retourne la liste d'entrée en sortie. 486 | 487 | {title="src/App.js",lang=javascript} 488 | ~~~~~~~~ 489 | this.state = { 490 | results: null, 491 | searchKey: '', 492 | searchTerm: DEFAULT_QUERY, 493 | error: null, 494 | isLoading: false, 495 | # leanpub-start-insert 496 | sortKey: 'NONE', 497 | # leanpub-end-insert 498 | }; 499 | ~~~~~~~~ 500 | 501 | Une fois que vous choisissez un `sortKey` différent, admettons la clé `AUTHOR`, vous trierez la liste avec la fonction de tri approprié issu de l'objet `SORTS`. 502 | 503 | Maintenant vous pouvez définir une nouvelle méthode de classe dans votre composant App qui simplement mute un `sortKey` vers votre état local du composant. Après quoi, le `sortKey` peut être utilisé pour retrouver la fonction de tri pour l'appliquer sur votre liste. 504 | 505 | {title="src/App.js",lang=javascript} 506 | ~~~~~~~~ 507 | class App extends Component { 508 | _isMounted = false; 509 | 510 | constructor(props) { 511 | 512 | // ... 513 | 514 | this.needsToSearchTopStories = this.needsToSearchTopStories.bind(this); 515 | this.setSearchTopStories = this.setSearchTopStories.bind(this); 516 | this.fetchSearchTopStories = this.fetchSearchTopStories.bind(this); 517 | this.onSearchSubmit = this.onSearchSubmit.bind(this); 518 | this.onSearchChange = this.onSearchChange.bind(this); 519 | this.onDismiss = this.onDismiss.bind(this); 520 | # leanpub-start-insert 521 | this.onSort = this.onSort.bind(this); 522 | # leanpub-end-insert 523 | } 524 | 525 | // ... 526 | 527 | # leanpub-start-insert 528 | onSort(sortKey) { 529 | this.setState({ sortKey }); 530 | } 531 | # leanpub-end-insert 532 | 533 | // ... 534 | 535 | } 536 | ~~~~~~~~ 537 | 538 | La prochaine étape est de passer la méthode et `sortKey` à votre composant Table. 539 | 540 | {title="src/App.js",lang=javascript} 541 | ~~~~~~~~ 542 | class App extends Component { 543 | 544 | // ... 545 | 546 | render() { 547 | const { 548 | searchTerm, 549 | results, 550 | searchKey, 551 | error, 552 | isLoading, 553 | # leanpub-start-insert 554 | sortKey 555 | # leanpub-end-insert 556 | } = this.state; 557 | 558 | // ... 559 | 560 | return ( 561 |
562 | // ... 563 |
571 | // ... 572 | 573 | ); 574 | } 575 | } 576 | ~~~~~~~~ 577 | 578 | Le composant Table est responsable de trier votre liste. Il prend une des fonctions de `SORT` à l'aide de `sortkey` et passe la liste d'entrée. Après quoi il conserve le mappage sur la liste triée. 579 | 580 | {title="src/App.js",lang=javascript} 581 | ~~~~~~~~ 582 | # leanpub-start-insert 583 | const Table = ({ 584 | list, 585 | sortKey, 586 | onSort, 587 | onDismiss 588 | }) => 589 | # leanpub-end-insert 590 |
591 | # leanpub-start-insert 592 | {SORTS[sortKey](list).map(item => 593 | # leanpub-end-insert 594 |
595 | // ... 596 |
597 | )} 598 |
599 | ~~~~~~~~ 600 | 601 | En théorie la liste devrait être triée par l'une des fonctions. Mais le tri par défaut est réglé à `NONE`, donc rien n'est encore trié. Jusqu'ici, personne éxecute la méthode `onSort()` pour changer le `sortKey`. Étendons la Table avec une ligne d'en-tête de colonne qui utilise les composants Sort dans les colonnes pour trier chaque colonne. 602 | 603 | {title="src/App.js",lang=javascript} 604 | ~~~~~~~~ 605 | const Table = ({ 606 | list, 607 | sortKey, 608 | onSort, 609 | onDismiss 610 | }) => 611 |
612 | # leanpub-start-insert 613 |
614 | 615 | 619 | Title 620 | 621 | 622 | 623 | 627 | Author 628 | 629 | 630 | 631 | 635 | Comments 636 | 637 | 638 | 639 | 643 | Points 644 | 645 | 646 | 647 | Archive 648 | 649 |
650 | # leanpub-end-insert 651 | {SORTS[sortKey](list).map(item => 652 | // ... 653 | )} 654 |
655 | ~~~~~~~~ 656 | 657 | Chaque composant Sort dispose d'une `sortKey` spécifique et de la fonction générale `onSort()`. Internement cela appelle la méthode avec la `sortKey` pour établir la clé spécifique. 658 | 659 | {title="src/App.js",lang=javascript} 660 | ~~~~~~~~ 661 | const Sort = ({ sortKey, onSort, children }) => 662 | 665 | ~~~~~~~~ 666 | 667 | Comme vous pouvez le voir, le composant Sort réutilise votre composant Button commun. Au clic d'un bouton chaque individuelle `sortKey` passée sera mutée par la méthode `onSort()`. Maintenant vous devez être capable de trier la liste lorsque vous cliquez sur les en-têtes de colonne. 668 | 669 | Il y a une amélioration mineure pour un visuel amélioré. Jusqu'ici, le bouton dans la colonne d'en-tête est un peu en décalé. Donnons au bouton dans le composant Sort un `className` approprié. 670 | 671 | {title="src/App.js",lang=javascript} 672 | ~~~~~~~~ 673 | const Sort = ({ sortKey, onSort, children }) => 674 | # leanpub-start-insert 675 | 682 | ~~~~~~~~ 683 | 684 | Maintenant, il doit avoir un ravissant aspect. Le prochain but serait d'également implémenter un tri inverse. La liste doit inverser le tri dès que vous cliquez deux fois sur le composant Sort. Premièrement, vous avez besoin de définir l'état inversé avec un booléen. Le tri peut être inversé ou non inversé. 685 | 686 | {title="src/App.js",lang=javascript} 687 | ~~~~~~~~ 688 | this.state = { 689 | results: null, 690 | searchKey: '', 691 | searchTerm: DEFAULT_QUERY, 692 | error: null, 693 | isLoading: false, 694 | sortKey: 'NONE', 695 | # leanpub-start-insert 696 | isSortReverse: false, 697 | # leanpub-end-insert 698 | }; 699 | ~~~~~~~~ 700 | 701 | Maintenant dans votre méthode de tri, vous pouvez évaluer si la liste est triée de façon inversée. C'est inversé si la `sortKey` dans l'état est la même que la `sortKey` entrante et que l'état inversé n'est pas déjà établi à true. 702 | 703 | {title="src/App.js",lang=javascript} 704 | ~~~~~~~~ 705 | onSort(sortKey) { 706 | # leanpub-start-insert 707 | const isSortReverse = this.state.sortKey === sortKey && !this.state.isSortReverse; 708 | this.setState({ sortKey, isSortReverse }); 709 | # leanpub-end-insert 710 | } 711 | ~~~~~~~~ 712 | 713 | De nouveau vous pouvez passer la propriété reverse à votre composant Table. 714 | 715 | {title="src/App.js",lang=javascript} 716 | ~~~~~~~~ 717 | class App extends Component { 718 | 719 | // ... 720 | 721 | render() { 722 | const { 723 | searchTerm, 724 | results, 725 | searchKey, 726 | error, 727 | isLoading, 728 | sortKey, 729 | # leanpub-start-insert 730 | isSortReverse 731 | # leanpub-end-insert 732 | } = this.state; 733 | 734 | // ... 735 | 736 | return ( 737 |
738 | // ... 739 |
748 | // ... 749 | 750 | ); 751 | } 752 | } 753 | ~~~~~~~~ 754 | 755 | Maintenant le Table doit avoir un *block body* de fonction fléchée pour calculer les données. 756 | 757 | {title="src/App.js",lang=javascript} 758 | ~~~~~~~~ 759 | # leanpub-start-insert 760 | const Table = ({ 761 | list, 762 | sortKey, 763 | isSortReverse, 764 | onSort, 765 | onDismiss 766 | }) => { 767 | const sortedList = SORTS[sortKey](list); 768 | const finalSortedList = isSortReverse 769 | ? sortedList.reverse() 770 | : sortedList; 771 | 772 | return( 773 | # leanpub-end-insert 774 |
775 |
776 | // ... 777 |
778 | # leanpub-start-insert 779 | {finalSortedList.map(item => 780 | # leanpub-end-insert 781 | // ... 782 | )} 783 |
784 | # leanpub-start-insert 785 | ); 786 | } 787 | # leanpub-end-insert 788 | ~~~~~~~~ 789 | 790 | Le tri inversé doit fonctionner maintenant. 791 | 792 | Enfin mais pas des moindres, vous devez traiter une question ouverte pour l'intérêt d'une une expérience utilisateur améliorée. Un utilisateur peut-il distinguer quelle colonne est activement trié? Jusqu'à présent, ce n'est pas possible. Donnons un retour visuel à l'utilisateur. 793 | 794 | Chaque composant Sort dispose déjà de sa `sortKey` spécifique. Elle pourrait être utilisée pour identifier le tri actif. Vous pouvez passer la `sortKey` depuis l'état interne du composant en tant que clé de tri actif pour votre composant Sort. 795 | 796 | {title="src/App.js",lang=javascript} 797 | ~~~~~~~~ 798 | const Table = ({ 799 | list, 800 | sortKey, 801 | isSortReverse, 802 | onSort, 803 | onDismiss 804 | }) => { 805 | const sortedList = SORTS[sortKey](list); 806 | const finalSortedList = isSortReverse 807 | ? sortedList.reverse() 808 | : sortedList; 809 | 810 | return( 811 |
812 |
813 | 814 | 821 | Title 822 | 823 | 824 | 825 | 832 | Author 833 | 834 | 835 | 836 | 843 | Comments 844 | 845 | 846 | 847 | 854 | Points 855 | 856 | 857 | 858 | Archive 859 | 860 |
861 | {finalSortedList.map(item => 862 | // ... 863 | )} 864 |
865 | ); 866 | } 867 | ~~~~~~~~ 868 | 869 | Maintenant dans votre composant Sort, vous savez à l'aide de la `sortKey` et de `activeSortKey` si le tri est actif. Donnez à votre composant un attribut `className` supplémentaire, dans le cas où il est trié, pour donner à l'utilisateur un retour visuel. 870 | 871 | {title="src/App.js",lang=javascript} 872 | ~~~~~~~~ 873 | # leanpub-start-insert 874 | const Sort = ({ 875 | sortKey, 876 | activeSortKey, 877 | onSort, 878 | children 879 | }) => { 880 | const sortClass = ['button-inline']; 881 | 882 | if (sortKey === activeSortKey) { 883 | sortClass.push('button-active'); 884 | } 885 | 886 | return ( 887 | 893 | ); 894 | } 895 | # leanpub-end-insert 896 | ~~~~~~~~ 897 | 898 | La manière de définir le `sortClass` est un peu malhabile, n'est ce pas? Il y a une petite bibliothèque sympa pour se débarrasser de çà. Premièrement vous devez l'installer. 899 | 900 | {title="Command Line",lang="text"} 901 | ~~~~~~~~ 902 | npm install classnames 903 | ~~~~~~~~ 904 | 905 | Et deuxièmement vous devez l'importer tout en haut du fichier *src/App.js*. 906 | 907 | {title="src/App.js",lang=javascript} 908 | ~~~~~~~~ 909 | import React, { Component } from 'react'; 910 | import axios from 'axios'; 911 | import { sortBy } from 'lodash'; 912 | # leanpub-start-insert 913 | import classNames from 'classnames'; 914 | # leanpub-end-insert 915 | import './App.css'; 916 | ~~~~~~~~ 917 | 918 | Maintenant vous pouvez l'utiliser pour définir votre `className` du composant avec des classes conditionnelles. 919 | 920 | {title="src/App.js",lang=javascript} 921 | ~~~~~~~~ 922 | const Sort = ({ 923 | sortKey, 924 | activeSortKey, 925 | onSort, 926 | children 927 | }) => { 928 | # leanpub-start-insert 929 | const sortClass = classNames( 930 | 'button-inline', 931 | { 'button-active': sortKey === activeSortKey } 932 | ); 933 | # leanpub-end-insert 934 | 935 | return ( 936 | # leanpub-start-insert 937 | 944 | ); 945 | } 946 | ~~~~~~~~ 947 | 948 | De nouveau, lorsque vous lancez vos tests, vous devez voir des tests d'instantanés échouant mais aussi des tests unitaires échouant pour le composant Table. Dû au fait que vous avez changé une nouvelle fois vos représentations de composant, vous pouvez accepter les tests instantanés. Mais vous devez réparer le test unitaire. Dans votre fichier *src/App.test.js*, vous avez besoin de fournir une `sortKey` et le booléen `isSortReverse` pour le composant Table. 949 | 950 | {title="src/App.test.js",lang=javascript} 951 | ~~~~~~~~ 952 | // ... 953 | 954 | describe('Table', () => { 955 | 956 | const props = { 957 | list: [ 958 | { title: '1', author: '1', num_comments: 1, points: 2, objectID: 'y' }, 959 | { title: '2', author: '2', num_comments: 1, points: 2, objectID: 'z' }, 960 | ], 961 | # leanpub-start-insert 962 | sortKey: 'TITLE', 963 | isSortReverse: false, 964 | # leanpub-end-insert 965 | }; 966 | 967 | // ... 968 | 969 | }); 970 | ~~~~~~~~ 971 | 972 | De nouveau vous pourriez avoir besoin d'accepter les tests d'instantané échouant pour votre composant Table, car vous avez fourni des propriétés étendues pour le composant Table. 973 | 974 | Enfin, votre interaction de tri avancé est maintenant terminée. 975 | 976 | ### Exercises: 977 | 978 | * utiliser une bibliothèque comme [Font Awesome](https://fontawesome.io/) pour indiquer le tri (inversé) 979 | * cela pourrait être une icône de flèche vers le haut ou de flèche vers le bas à côté de chaque en-tête Sort 980 | * lire plus à propos de la [bibliothèque classnames](https://github.com/JedWatson/classnames) 981 | 982 | {pagebreak} 983 | 984 | Vous avez appris les techniques de composant avancées dans React! Récapitulons les derniers chapitres : 985 | 986 | * React 987 | * l'attribut `ref` pour référencer les éléments du DOM 988 | * les components d'ordre supérieur sont un moyen courant de construire des composants avancés 989 | * l'implementation d'interactions avancées dans React 990 | * les classNames conditionnels avec une élégante bibliothèque assistante 991 | * ES6 992 | * la décomposition du reste pour séparer les objets et tableaux 993 | 994 | Vous pouvez trouver le code source sur le [dépôt officiel](https://github.com/the-road-to-learn-react/hackernews-client/tree/5.5). 995 | -------------------------------------------------------------------------------- /manuscript/chapter6.md: -------------------------------------------------------------------------------- 1 | # Gestion de l'état au sein de React et au-delà 2 | 3 | Vous avez déjà appris les basiques de la gestion d'état dans React dans les chapitres précédents. Ce chapitre creuse ce sujet un peu plus profondément. Vous apprendrez les meilleurs pratiques, comment les appliquer et pourquoi vous pouvez envisager l'usage d'une bibliothèque tierce de gestion d'état. 4 | 5 | ## L'élévation de l'état 6 | 7 | Seule le composant App est un composant ES6 stateful dans votre application. Il gère beaucoup d'aspects de l'état et de la logique de l'application au sein de ses méthodes. Peut-être avez-vous remarqué que vous passez beaucoup de propriétés à votre composant Table. La plupart de ces propriétés sont seulement utilisées dans le composant Table. En conclusion une personne pourrez soutenir que c'est un non-sens que le composant App connaisse toutes ces propriétés. 8 | 9 | L'entièreté de la fonctionnalité de tri est seulement utilisé dans le composant Table. Vous pourriez la migrer dans le composant Table, car le composant App n'en a pas du tout besoin. Le processus de refactoring en sous-état d'un composant vers un autre est connu comme *lifting state*. Dans votre cas, vous voulez migrer l'état qui n'est pas utilisé dans le composant App à l'intérieur du composant Table. L'état est déplacé vers le bas depuis le parent vers le composant enfant. 10 | 11 | Dans le but de traiter avec l'état et les méthodes de classe dans le composant Table, il doit devenir un composant de classe ES6. Le refactoring d'un composant fonctionnel stateless vers un composant de classe ES6 est trivial. 12 | 13 | Voici votre composant Table comme un composant fonctionnel stateless : 14 | 15 | {title="src/App.js",lang=javascript} 16 | ~~~~~~~~ 17 | const Table = ({ 18 | list, 19 | sortKey, 20 | isSortReverse, 21 | onSort, 22 | onDismiss 23 | }) => { 24 | const sortedList = SORTS[sortKey](list); 25 | const reverseSortedList = isSortReverse 26 | ? sortedList.reverse() 27 | : sortedList; 28 | 29 | return ( 30 | // ... 31 | ); 32 | } 33 | ~~~~~~~~ 34 | 35 | Voici votre composant Table comme un composant de classe ES6 : 36 | 37 | {title="src/App.js",lang=javascript} 38 | ~~~~~~~~ 39 | # leanpub-start-insert 40 | class Table extends Component { 41 | render() { 42 | const { 43 | list, 44 | sortKey, 45 | isSortReverse, 46 | onSort, 47 | onDismiss 48 | } = this.props; 49 | 50 | const sortedList = SORTS[sortKey](list); 51 | const reverseSortedList = isSortReverse 52 | ? sortedList.reverse() 53 | : sortedList; 54 | 55 | return( 56 | // ... 57 | ); 58 | } 59 | } 60 | # leanpub-end-insert 61 | ~~~~~~~~ 62 | 63 | Puisque vous voulez traiter l'état et les méthodes dans votre composant, vous devez ajouter un constructeur et un état initial. 64 | 65 | {title="src/App.js",lang=javascript} 66 | ~~~~~~~~ 67 | class Table extends Component { 68 | # leanpub-start-insert 69 | constructor(props) { 70 | super(props); 71 | 72 | this.state = {}; 73 | } 74 | # leanpub-end-insert 75 | 76 | render() { 77 | // ... 78 | } 79 | } 80 | ~~~~~~~~ 81 | 82 | Maintenant vous pouvez migrer l'état et les méthodes de classe concernant la fonctionnalité de tri depuis votre composant App vers votre composant Table de dessous. 83 | 84 | {title="src/App.js",lang=javascript} 85 | ~~~~~~~~ 86 | class Table extends Component { 87 | constructor(props) { 88 | super(props); 89 | 90 | # leanpub-start-insert 91 | this.state = { 92 | sortKey: 'NONE', 93 | isSortReverse: false, 94 | }; 95 | 96 | this.onSort = this.onSort.bind(this); 97 | # leanpub-end-insert 98 | } 99 | 100 | # leanpub-start-insert 101 | onSort(sortKey) { 102 | const isSortReverse = this.state.sortKey === sortKey && !this.state.isSortReverse; 103 | this.setState({ sortKey, isSortReverse }); 104 | } 105 | # leanpub-end-insert 106 | 107 | render() { 108 | // ... 109 | } 110 | } 111 | ~~~~~~~~ 112 | 113 | N'oubliez pas de supprimer l'état déplacé et la méthode de classe `onSort()` de votre composant App. 114 | 115 | {title="src/App.js",lang=javascript} 116 | ~~~~~~~~ 117 | class App extends Component { 118 | _isMounted = false; 119 | 120 | constructor(props) { 121 | super(props); 122 | 123 | this.state = { 124 | results: null, 125 | searchKey: '', 126 | searchTerm: DEFAULT_QUERY, 127 | error: null, 128 | isLoading: false, 129 | }; 130 | 131 | this.setSearchTopStories = this.setSearchTopStories.bind(this); 132 | this.fetchSearchTopStories = this.fetchSearchTopStories.bind(this); 133 | this.onDismiss = this.onDismiss.bind(this); 134 | this.onSearchSubmit = this.onSearchSubmit.bind(this); 135 | this.onSearchChange = this.onSearchChange.bind(this); 136 | this.needsToSearchTopStories = this.needsToSearchTopStories.bind(this); 137 | } 138 | 139 | // ... 140 | 141 | } 142 | ~~~~~~~~ 143 | 144 | De plus, vous pouvez faire une API allégée du composant Table. Supprimez les propriétés qui lui étaient passées depuis le composant App, car elles sont maintenant gérées dans le composant Table de façon interne. 145 | 146 | {title="src/App.js",lang=javascript} 147 | ~~~~~~~~ 148 | class App extends Component { 149 | 150 | // ... 151 | 152 | render() { 153 | # leanpub-start-insert 154 | const { 155 | searchTerm, 156 | results, 157 | searchKey, 158 | error, 159 | isLoading 160 | } = this.state; 161 | # leanpub-end-insert 162 | 163 | // ... 164 | 165 | return ( 166 |
167 | // ... 168 | { error 169 | ?
170 |

Something went wrong.

171 |
172 | :
178 | } 179 | // ... 180 | 181 | ); 182 | } 183 | } 184 | ~~~~~~~~ 185 | 186 | Maintenant dans votre composant Table vous pouvez utiliser la méthode interne `onSort()` et l'état interne de Table. 187 | 188 | {title="src/App.js",lang=javascript} 189 | ~~~~~~~~ 190 | class Table extends Component { 191 | 192 | // ... 193 | 194 | render() { 195 | # leanpub-start-insert 196 | const { 197 | list, 198 | onDismiss 199 | } = this.props; 200 | 201 | const { 202 | sortKey, 203 | isSortReverse, 204 | } = this.state; 205 | # leanpub-end-insert 206 | 207 | const sortedList = SORTS[sortKey](list); 208 | const reverseSortedList = isSortReverse 209 | ? sortedList.reverse() 210 | : sortedList; 211 | 212 | return( 213 |
214 |
215 | 216 | 223 | Title 224 | 225 | 226 | 227 | 234 | Author 235 | 236 | 237 | 238 | 245 | Comments 246 | 247 | 248 | 249 | 256 | Points 257 | 258 | 259 | 260 | Archive 261 | 262 |
263 | { reverseSortedList.map((item) => 264 | // ... 265 | )} 266 |
267 | ); 268 | } 269 | } 270 | ~~~~~~~~ 271 | 272 | Votre application doit encore fonctionner. Mais vous avez fait un refactoring crucial. Vous avez déplacé la fonctionnalité et l'état plus près dans un autre composant. Les autres composants ont été allégés. De plus l'API du composant Table a été allégé car il traite la fonctionnalité de tri de façon interne. 273 | 274 | Le processus de *lifting state* peut aller dans l'autre sens également : depuis le composant enfant vers le composant parent. Cela s'appelle le *lifting state up*. Imaginez-vous vous occupiez également de l'état interne dans un composant enfant. Maintenant vous devriez satisfaire également un besoin de montrer l'état dans votre composant parent. Vous devriez élever l'état vers votre composant parent. Mais cela va plus loin. Imaginez vous souhaitez montrer l'état dans un composant frère de votre composant enfant. De nouveau vous devriez élever l'état vers votre composant parent. Le composant parent traite l'état interne, mais l'expose vers les deux composants enfants. 275 | 276 | ### Exercises: 277 | 278 | * lire plus à propos de l'[élévation de l'état en React](https://reactjs.org/docs/lifting-state-up.html) 279 | * lire plus à propos du lifting state dans [React avant l'utilisation de Redux](https://www.robinwieruch.de/learn-react-before-using-redux/) 280 | 281 | ## setState() : revisité 282 | 283 | Jusqu'ici vous devez utiliser `setState()` de React pour gérer votre état de composant interne. Vous pouvez transmettre un objet à une fonction qui vous permet de mettre à jour partiellement l'état interne. 284 | 285 | {title="Code Playground",lang="javascript"} 286 | ~~~~~~~~ 287 | this.setState({ foo: bar }); 288 | ~~~~~~~~ 289 | 290 | Mais `setState()` ne prend pas seulement un objet. Dans sa seconde version, vous pouvez transmettre une fonction pour mettre à jour l'état. 291 | 292 | {title="Code Playground",lang="javascript"} 293 | ~~~~~~~~ 294 | this.setState((prevState, props) => { 295 | // ... 296 | }); 297 | ~~~~~~~~ 298 | 299 | Pourquoi vouloir faire cela? Il y a un des cas d'utilisation cruciaux où il fait sens d'utiliser une fonction à la place d'un objet. C'est quand vous mettez à jour l'état en fonction de votre état précédent ou des propriétés. Si vous n'utilisez pas une fonction, la gestion interne d'état peut engendrer des bugs. 300 | 301 | Mais pourquoi cela cause des bugs d'utiliser un objet à la place d'une fonction lorsque la mise à jour dépend de l'état précédent ou des propriétés? La méthode `setState()` de React est asynchrone. React regroupe les appelles de `setState()` et les exécute finalement. Il peut arriver que l'état précédent ou que les propriétés soient modifiés entre-temps alors vous souhaitez vous fier à eux dans votre appelle `setState()`. 302 | 303 | {title="Code Playground",lang="javascript"} 304 | ~~~~~~~~ 305 | const { fooCount } = this.state; 306 | const { barCount } = this.props; 307 | this.setState({ count: fooCount + barCount }); 308 | ~~~~~~~~ 309 | 310 | Imaginez `fooCount` et `barCount`, c'est-à-dire l'état ou les propriétés, changent autre part de façon asynchrone lorsque vous appelez `setState()`. Dans une application grandissante, vous avez plus qu'un appelle à `setState()` au travers de votre application. Puisque `setState()` s'exécute de façon asynchrone, vous pourriez dépendre dans cet exemple de valeurs périmées. 311 | 312 | Avec l'approche par fonction, la fonction dans `setState()` est une fonction de rappel (callback) qui opère sur l'état et les propriétés au moment de l'exécution de la fonction de rappel. Bien que `setState()` soit asynchrone, avec une fonction il prend l'état et les propriétés au moment de quand c'était exécuté. 313 | 314 | {title="Code Playground",lang="javascript"} 315 | ~~~~~~~~ 316 | this.setState((prevState, props) => { 317 | const { fooCount } = prevState; 318 | const { barCount } = props; 319 | return { count: fooCount + barCount }; 320 | }); 321 | ~~~~~~~~ 322 | 323 | Maintenant, retournons à votre code pour réparer ce comportement. Ensemble nous allons le réparer à un endroit où `setState()` est utilisé et dépend de l'état et des propriétés. Après quoi, vous serez capable de l'appliquer à d'autres endroits également. 324 | 325 | La méthode `setSearchTopStories()` dépend de l'état précédent c'est donc un parfait exemple pour utiliser une fonction à la place d'un objet dans `setState()`. Pour l'heure, cela ressemble au bout de code suivant. 326 | 327 | {title="src/App.js",lang=javascript} 328 | ~~~~~~~~ 329 | setSearchTopStories(result) { 330 | const { hits, page } = result; 331 | const { searchKey, results } = this.state; 332 | 333 | const oldHits = results && results[searchKey] 334 | ? results[searchKey].hits 335 | : []; 336 | 337 | const updatedHits = [ 338 | ...oldHits, 339 | ...hits 340 | ]; 341 | 342 | this.setState({ 343 | results: { 344 | ...results, 345 | [searchKey]: { hits: updatedHits, page } 346 | }, 347 | isLoading: false 348 | }); 349 | } 350 | ~~~~~~~~ 351 | 352 | Vous extrayez les valeurs de l'état, mais vous mettez à jour l'état en fonction de l'état précédent de façon asynchrone. 353 | 354 | {title="src/App.js",lang=javascript} 355 | ~~~~~~~~ 356 | setSearchTopStories(result) { 357 | const { hits, page } = result; 358 | 359 | # leanpub-start-insert 360 | this.setState(prevState => { 361 | // ... 362 | }); 363 | # leanpub-end-insert 364 | } 365 | ~~~~~~~~ 366 | 367 | Vous pouvez déplacer le bloc en entier que vous avez déjà implémenté à l'intérieur de la fonction. Vous avez seulement à remplacer le fait que vous opérez sur le `prevState` plutôt que `this.state`. 368 | 369 | {title="src/App.js",lang=javascript} 370 | ~~~~~~~~ 371 | setSearchTopStories(result) { 372 | const { hits, page } = result; 373 | 374 | this.setState(prevState => { 375 | # leanpub-start-insert 376 | const { searchKey, results } = prevState; 377 | 378 | const oldHits = results && results[searchKey] 379 | ? results[searchKey].hits 380 | : []; 381 | 382 | const updatedHits = [ 383 | ...oldHits, 384 | ...hits 385 | ]; 386 | 387 | return { 388 | results: { 389 | ...results, 390 | [searchKey]: { hits: updatedHits, page } 391 | }, 392 | isLoading: false 393 | }; 394 | # leanpub-end-insert 395 | }); 396 | } 397 | ~~~~~~~~ 398 | 399 | Cela réparera notre problème d'état périmé. Il y a une amélioration supplémentaire. Puisque c'est une fonction, vous pouvez extraire la fonction pour un gain de lisibilité. C'est l'un des avantages d'utiliser une fonction au lieu d'un objet. La fonction peut vivre à l'extérieur du composant. Mais vous devez utiliser une fonction d'ordre supérieur pour transmettre le résultat. En fin de compte, vous souhaitez mettre à jour l'état basé sur le résultat rapporté de l'API. 400 | 401 | {title="src/App.js",lang=javascript} 402 | ~~~~~~~~ 403 | setSearchTopStories(result) { 404 | const { hits, page } = result; 405 | this.setState(updateSearchTopStoriesState(hits, page)); 406 | } 407 | ~~~~~~~~ 408 | 409 | La fonction `updateSearchTopStoriesState()`retourne une fonction. C'est une fonction d'ordre supérieur. Vous pouvez définir cette fonction d'ordre supérieur à l'extérieur de votre composant App. Notez comment la signature de la fonction change légèrement. 410 | 411 | {title="src/App.js",lang=javascript} 412 | ~~~~~~~~ 413 | # leanpub-start-insert 414 | const updateSearchTopStoriesState = (hits, page) => (prevState) => { 415 | const { searchKey, results } = prevState; 416 | 417 | const oldHits = results && results[searchKey] 418 | ? results[searchKey].hits 419 | : []; 420 | 421 | const updatedHits = [ 422 | ...oldHits, 423 | ...hits 424 | ]; 425 | 426 | return { 427 | results: { 428 | ...results, 429 | [searchKey]: { hits: updatedHits, page } 430 | }, 431 | isLoading: false 432 | }; 433 | }; 434 | # leanpub-end-insert 435 | 436 | class App extends Component { 437 | // ... 438 | } 439 | ~~~~~~~~ 440 | 441 | C'est tout. La fonction à la place de l'approche objet dans `setState()` résout de potentiels bugs et améliore la lisibilité et maintenabilité de votre code. De plus, elle devient testable à l'extérieur du composant App. Vous pouvez l'exporter et écrire un test pour vous exercer. 442 | 443 | ### Exercise: 444 | 445 | * lire plus à propos de l'[utilisation correcte de l'état dans React](https://reactjs.org/docs/state-and-lifecycle.html#using-state-correctly) 446 | * exporter updateSearchTopStoriesState du fichier 447 | * écrire un test pour cela qui passe un *payload* (hits, page) et un état précédent crée et finalement attendre un nouvel état 448 | * refactorer vos méthodes `setState()` utiliser une fonction 449 | * mais seulement quand cela fait sens, c'est-à-dire lorsqu'il dépend de l'état ou des propriétés 450 | * lancer vos tests de nouveau et vérifier que tout est à jour 451 | 452 | ## Apprivoiser l'état 453 | 454 | Les chapitres précédents vous ont montrés que la gestion de l'état peut être un sujet crucial dans les applications imposantes. De façon générale, pas seulement React mais beaucoup de frameworks SPA luttent avec çà. Les applications deviennent plus complexes depuis quelques années. Un des gros challenges dans les applications web de nos jours est d'apprivoiser et contrôler l'état. 455 | 456 | Comparé aux autres solutions, React à déjà fait un grand pas en avant. Le flux de données unidirectionnel et une API simple pour gérer l'état dans un composant sont indispensables. Ces concepts le rendent plus simple pour raisonner au sujet de votre état ainsi que de vos changements d'états. Cela rend plus simple de raisonner au niveau composant et d'un certain point au niveau applicatif. 457 | 458 | Dans une application grandissante, cela devient plus difficile de raisonner au sujet des changements d'état. Vous pouvez introduire des bugs en agissant sur des états périmés lors de l'utilisation d'un objet à la place d'une fonction dans `setState()`. Vous devez élever l'état pour partager le nécessaire ou cacher l'état non nécessaire au travers des composants. Il peut arriver qu'un composant est besoin d'élever son état vers le haut, car ses composants frères dépendent de ce dernier. Peut-être le composant est éloigné dans l'arbre de composant et ainsi vous devrez partager l'état au travers de l'ensemble de l'arbre de composant. En conclusion les composants seront impliqués dans la gestion d'état dans de bien plus grandes mesures. Mais après tout, la principale responsabilité des composants devraient être la représentation de l'UI (interface utilisateur), n'est ce pas? 459 | 460 | Pour toutes ces raisons, il existe des solutions autonomes pour prendre en charge la gestion de l'état. Ces solutions ne sont pas seulement utilisées dans React. Cependant, cela fait de l'écosystème React un outil extrêmement puissant. Vous pouvez utiliser différentes solutions pour résoudre vos problèmes. Confier le problème de la mise à l'échelle de la gestion de l'état, vous pourriez avoir entendu parler des bibliohtèques [Redux](http://redux.js.org/docs/introduction/) ou [MobX](https://mobx.js.org/). Vous pouvez utiliser l'une de ces solutions dans une application React. Elles arrivent avec des extensions, [react-redux](https://github.com/reactjs/react-redux) et [mobx-react](https://github.com/mobxjs/mobx-react), pour les intégrer à l'intérieur de la couche vue de React. 461 | 462 | Redux et MobX sont en dehors du cadre de ce livre. Lorsque vous avez fini le livre, vous obtiendrez des conseils sûrs comment vous pouvez continuer à apprendre React et son écosystème. Un cheminement d'apprentissage pourrait être l'apprentissage de Redux. Avant que vous plongez dans le sujet de la gestion d'état externe, je peux vous recommander de lire cette [article](https://www.robinwieruch.de/redux-mobx-confusion/). Il a pour but de vous donner une meilleure compréhension de comment apprendre la gestion d'état externe. 463 | 464 | ### Exercices : 465 | 466 | * lire plus à propos de la [gestion d'état externe et de comment l'apprendre](https://www.robinwieruch.de/redux-mobx-confusion/) 467 | * regarder mon second livre à propos de la [gestion de l'état dans React](https://roadtoreact.com/) 468 | 469 | {pagebreak} 470 | 471 | Vous avez appris la gestion d'état avancé dans React! Récapitulons les derniers chapitres : 472 | 473 | * React 474 | * élévation de la gestion de l'état haut et bas vers les composants appropriés 475 | * `setState()` peut utiliser une fonction pour empêcher des bugs d'état périmé 476 | * les solutions externes existantes qui vous aident à apprivoiser l'état 477 | 478 | Vous pouvez trouver le code source sur le [dépôt officiel](https://github.com/the-road-to-learn-react/hackernews-client/tree/5.6). 479 | -------------------------------------------------------------------------------- /manuscript/contributor.md: -------------------------------------------------------------------------------- 1 | # Contributeurs 2 | 3 | Plusieurs personnes ont rendu possible l'écriture et l'amélioration de *The Road to learn React* au fur et à mesure. Actuellement, c'est l'un des livres React.js les plus téléchargés. Originellement le livre a été écrit par l'Ingénieur Logiciel allemand [Robin Wieruch](https://www.robinwieruch.de/). Mais toutes les traductions du livre ne seraient pas possibles sans l'aide de collaborateurs. Cette version du livre a été traduite par l'Ingénieur Logiciel français [Guillaume Borg](https://www.linkedin.com/in/guillaume-borg-0904b8a8/) publiant du contenu portant sur des technologies Web autour du JavaScript et du W3C. Son contenu est en premier lieu francophone et accessible via sa [chaîne Youtube](https://www.youtube.com/c/EchyzenWebsite), son [compte Twitter](https://twitter.com/EchyzenWebsite) ainsi que son [compte Github](https://github.com/GuillaumeUnice). 4 | 5 | {pagebreak} -------------------------------------------------------------------------------- /manuscript/deployChapter.md: -------------------------------------------------------------------------------- 1 | # Dernière étape pour la mise en production 2 | 3 | Les derniers chapitres vous montreront comment déployer votre application en production. Vous utiliserez le service d'hébergement gratuit Heroku. Lors du déploiement de votre application, vous en apprendrez plus sur *create-react-app*. 4 | 5 | ## Eject 6 | 7 | L'étape suivante et les connaissances liées ne sont **pas nécessaires** pour déployer votre application en production. Cependant je souhaite vous l'expliquer. *create-react-app* arrive avec une fonctionnalité qui le rend extensible mais aussi empêche une clientèle captive. Une clientèle captive se produit habituellement lorsque vous achetez une technologie mais qu'il n'y a pas de trappe d'évacuation pour son usage futur. Heureusement dans *create-react-app* vous disposez d'une telle trappe à l'aide d'**eject**. 8 | 9 | Dans votre *package.json* vous trouverez les scripts pour *start*, *test* et *build* votre application. Le dernier script est *eject*. Vous pouvez l'essayer, mais il n'y a aucun moyen de faire chemin inverse. **C'est une opération à sens unique. Une fois que vous éjectez, vous ne pouvez revenir en arrière!** si vous venez juste de démarrer l'apprentissage de React, cela n'a aucun intérêt de quitter l'environnement commode de *create-react-app*. 10 | 11 | Si vous souhaitez lancer `npm run eject`, la commande fera une copie de toute la configuration et des dépendances vers votre *package.json* et un nouveau dossier *config/*. Vous souhaiteriez convertir le projet complet dans une installation customisée comprenant l'outillage incluant Babel et Webpack. Après quoi, vous possèderiez un contrôle absolu sur tous ces outils. 12 | 13 | La documentation officielle dit que *create-react-app* est adaptée pour des projets de petite à moyenne taille. Vous ne devez pas vous sentir obligé d'utiliser la commande "eject". 14 | 15 | ### Exercices : 16 | 17 | * lire plus à propos d'[eject]((https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/README.md#npm-run-eject) 18 | 19 | ## Déployer votre application 20 | 21 | Au bout du compte, aucune application ne devrait rester en local. Vous souhaitez la mettre en ligne. Heroku est un PaaS (Platform as a Service) où vous pouvez héberger votre application. Ils offrent une intégration transparente avec React. Pour être plus précis : il est possible de déployer une application *create-react-app* en quelques minutes. C'est un déploiement avec zéro-configuration qui suit la philosophie de *create-react-app*. 22 | 23 | Vous avez besoin de remplir deux prérequis avant de pouvoir déployer votre application sur Heroku : 24 | 25 | * installer le [CLI d'Heroku](https://devcenter.heroku.com/articles/heroku-cli) 26 | * créer un [ compte Heroku gratuit](https://www.heroku.com/) 27 | 28 | Si vous avez installé Homebrew, vous pouvez installer le CLI d'Heroku en ligne de commande : 29 | 30 | {title="Command Line",lang="text"} 31 | ~~~~~~~~ 32 | brew update 33 | brew install heroku-toolbelt 34 | ~~~~~~~~ 35 | 36 | Maintenant vous pouvez utiliser Git et le CLI d'Heroku pour déployer votre application. 37 | 38 | {title="Command Line",lang="text"} 39 | ~~~~~~~~ 40 | git init 41 | heroku create -b https://github.com/mars/create-react-app-buildpack.git 42 | git add . 43 | git commit -m "react-create-app on Heroku" 44 | git push heroku master 45 | heroku open 46 | ~~~~~~~~ 47 | 48 | C'est tout. Maintenant, j'espère que votre application a démarré et est en cours d'exécution. Si vous rencontrez des problèmes vous pouvez vérifier les ressources suivantes : 49 | 50 | * [Git et GitHub Essentials](https://www.robinwieruch.de/git-essential-commands/) 51 | * [Déploiement de React avec zéro-configuration](https://blog.heroku.com/deploying-react-with-zero-configuration) 52 | * [Heroku Buildpack pour create-react-app](https://github.com/mars/create-react-app-buildpack) 53 | -------------------------------------------------------------------------------- /manuscript/finalwords.md: -------------------------------------------------------------------------------- 1 | # Plan 2 | 3 | C'était le dernier chapitre du livre. J'espère que vous avez apprécié la lecture et qu'elle vous a aidé à saisir React. Si vous avez aimé le livre, partagez-le comme moyen d'apprendre React auprès de vos amis. Il pourrait tout à fait être un cadeau. De plus, cela représente beaucoup pour moi que vous prenez 5 minutes pour écrire un avis sur [Amazon](https://www.amazon.com/dp/B077HJFCQX) ou [Goodreads](https://www.goodreads.com/book/show/37503118-the-road-to-learn-react). 4 | 5 | **Mais vers où aller après avoir lu ce livre?** Vous pouvez soit approfondir l'application de vous-même ou partager votre propre projet React. Avant que vous plongez dans un autre livre, cours ou tutoriel, vous devriez créer votre propre projet React en pratique. Faite le pendant une semaine, mettez-la en production en le déployant quelque part, et contactez-moi sur [Twitter](https://twitter.com/rwieruch) pour l'exposer. Je suis curieux de ce que vous allez construire après que vous ayez lu le livre. 6 | 7 | Si vous recherchez des voies de poursuites supplémentaires pour votre application, je peux recommander quelques chemins d'apprentissage après que vous ayez utilisé seulement du simple React dans ce livre : 8 | 9 | * **La gestion d'état :** Vous avez utilisé `this.setState()` et `this.state` de React pour manager et accéder à l'état local du composant. C'est parfait pour débuter. Cependant, dans une application plus imposante vous rencontrerez les [limites de l'état local de composant React](https://www.robinwieruch.de/learn-react-before-using-redux/). Par conséquent, vous pouvez utiliser une bibliothèque tierce de gestion d'état telle que [Redux ou MobX] (https://www.robinwieruch.de/redux-mobx-confusion/). Sur la plateforme de cours [Road to React](https://roadtoreact.com/), vous trouverez "Taming the State in React" qui apprend l'état local dans React de façon avancé, Redux et MobX. Le cours arrive avec un ebook également, mais je recommande tout le monde de se plonger dans le code source et aussi dans les captures d'écrans. Si vous avez aimé ce livre, vous devrez sans aucun doute regarder "Taming the State in React". 10 | 11 | * **Se connecter à une base de données et/ou s'authentifier :** Dans une application React grandissante, vous pourrez finalement désirer persister vos données. Les données devraient être stockées dans une base de données ainsi elles peuvent survivre après la session du navigateur et être partagé auprès de divers utilisateurs utilisant l'application. La manière la plus simple d'introduire une base de données est l'utilisation de Firebase. Dans [ce tutoriel abordable](https://www.robinwieruch.de/complete-firebase-authentication-react-tutorial/), vous trouverez un guide étape par étape sur comment utiliser l'authentification de Firebase (inscription, identification, déconnexion, ...) au sein de React. Au-delà de cela vous utiliserez la base de données en temps réel de Firebase pour enregistrer les entités des utilisateurs. Après quoi, c'est à vous de stocker plus de données issues de votre application. 12 | 13 | * **Outillage avec Webpack et Babel :** Dans le livre vous avez utilisé *create-react-app* pour installer votre application. À certains moments, une fois que vous avez appris React, vous pourriez être amené à apprendre l'outillage autour. Cela vous permet d'installer votre propre projet sans *create-react-app*. Je peux recommander de suivre une installation minimale avec [Webpack and Babel](https://www.robinwieruch.de/minimal-react-webpack-babel-setup/). Après quoi vous pouvez appliquer de vous-même plus d'outils. Par exemple, vous pourrez [utiliser ESLint](https://www.robinwieruch.de/react-eslint-webpack-babel/) pour contraindre un code style unifié au sein de votre application. 14 | 15 | * **Syntaxe de composant React :** Les possibilités et bonnes pratiques pour implémenter les composants React évoluent au fil du temps. Vous trouverez dans d'autres ressources d'apprentissages, plusieurs manières d'écrire vos composants React, en particulier les composants de classe React. Vous pouvez vous renseignez sur [ce dépôt GitHub](https://github.com/the-road-to-learn-react/react-alternative-class-component-syntax) pour trouver des façons alternatives d'écrire les composants de classe React. En utilisant les déclarations de champs de classe, vous pouvez les écrire encore plus concisément dans le futur. 16 | 17 | * **Projets d'échantillon :** Après l'apprentissage en pur React, c'est toujours bon d'appliquer les connaissances en premier au sein de votre projet avant de reprendre l'apprentissage de nouveau. Vous pouvez écrire votre propre jeu tic-tac-toe ou une simple calculette en React. Il y a beaucoup de tutoriels par-ci par-là qui utilisent React pour construire des choses formidables. Regardez ma construction [d'une liste paginée à défilement infini] (https://www.robinwieruch.de/react-paginated-list/), ou [connecter votre application React à des cartes bancaires pour recharger de l'argent](https://www.robinwieruch.de/react-express-stripe-payment/). Expérimentez avec ces mini-applications pour être à l'aise avec React. 18 | 19 | * **Composants UI :** Vous ne devez pas faire l'erreur d'introduire trop tôt une bibliothèque de composant UI dans votre projet. Premièrement, vous devez apprendre comment implémenter et utiliser à partir de rien un *dropdown*, une *checkbox* ou un *dialog* au sein de React avec des éléments HTML standards. La major partie de ces composants gèreront leur propre état local. Une *checkbox* doit connaître si elle est coché ou non coché. Ainsi vous devez les implémenter en tant que composants controllés. Après que vous ayez fait face à toutes les implémentations fondamentales, vous pouvez introduire une bibliohtèque de composant UI qui vous fournit des composants React *checkboxes* et *dialogs*. 20 | You shouldn't make the mistake to introduce too early a UI component library in your project. First, you should learn how to implement and use a dropdown, checkbox or dialog in React with standard HTML elements from scratch. The major part of these components will manage their own local state. A checkbox has to know whether it is checked or not checked. Thus you should implement them as controlled components. After you went through all the foundational implementations, you can introduce a UI component library which gives you checkboxes and dialogs as React components. 21 | 22 | * **Organisation du code :** Au cours de la lecture du livre, vous avez rencontré un chapitre portant sur l'organisation du code. Vous pouvez appliquer ces changements maintenant, si vous n'avez pas encore eu l'occasion de le faire. Cela organisera vos composants au sein de fichiers et dossiers (modules) structurés. De plus, cela vous aidera à comprendre et apprendre les principes de séparation de code, réutilisabilité, maintenabilité et de conception de d'API de module. Finalement, votre application grossira et vous aurez besoin de la structurer en modules. Donc il est bon pour vous de commencer dès aujourd'hui. 23 | 24 | * **Testing :** Le livre aborde seulement en surface la phase de test. Si vous n'êtes pas famillié avec ce thème en général, vous pouvez approfondir les concepts de test unitaire et de test d'intégration, notamment dans le contexte d'application React. Sur le plan de l'implémentation, je vous recommanderai de vous en tenir à Enzyme et Jest dans le but d'améliorer votre approche des tests avec les tests unitaires et les snapshots test de React. 25 | 26 | * **Routage :** Vous pouvez implémenter un routage pour votre application avec [react-router](https://github.com/ReactTraining/react-router). Jusqu'ici, vous avez seulement une page dans votre application. Le React Router vous aide à obtenir plusieurs pages avec plusieurs URLs. Quand vous introduisez le routage pour votre application, vous ne réalisez aucune requête auprès de votre serveur web pour requêter la prochaine page. Le routeur fera tout pour vous côté client. Donc essayez vous et mettez vos mains dans le cambouis en introduisant le routage dans votre application. 27 | 28 | * **Type Checking :** Dans un chapitre, vous avez utilisé React PropTypes pour définir les interfaces des composants. C'est en général une bonne pratique pour éviter les bugs. Mais les PropTypes sont vérifiés seulement à l'exécution. Vous pouvez pousser le curseur plus loin en introduisant la vérification à la compilation par typage statique. [TypeScript](https://www.typescriptlang.org/) est une solution populaire. Mais dans l'écosystème React, les utilisateurs utilisent souvent [Flow](https://flowtype.org/). Je peux recommander de prêter une attention à Flow si vous êtes intéressé par l'obtention d'application plus robuste. 29 | 30 | * **React Native :** [React Native](https://facebook.github.io/react-native/) amène votre application dans les périphériques mobiles. Vous pouvez appliquer vos acquis de React pour délivrer des applications IOS et Android. La courbe d'apprentissage, une fois React apprit, ne devrez pas être si abrupte pour React Native. Les deux partages les mêmes principes. Vous rencontrerez seulement différent niveau de composants sur mobile que ce que vous avez utilisé au sein d'applications web. 31 | 32 | En général, je vous invite à visiter mon [site](https://www.robinwieruch.de) pour trouver des sujets intéressant à propos du développement web et de l'ingénierie logiciel. Vous pouvez [souscrire à ma newsletter](https://www.getrevue.co/profile/rwieruch) pour être mis au courant sur des articles, livres et cours. De plus, la plateforme de cours [Road to React](https://roadtoreact.com) offre des cours plus avancés pour apprendre l'écosystème React. Foncez! 33 | 34 | Enfin mais pas des moindres, j'espère trouver plus de [Patrons](https://www.patreon.com/rwieruch) qui sont prêts à supporter mon contenu. Il y a beaucoup d'étudiants là-bas qui ne peuvent pas se permettre de payer du contenu éducatif. C'est pourquoi je poste beaucoup de contenus gratuits là-bas gratuitement. En me supportant dans mes actions en tant que Patron, je peux durablement continuer ces efforts d'éducation gratuitement. 35 | 36 | Une fois encore, si vous aimez le livre, je souhaiterais que vous preniez le temps de penser à propos de potentielle personne qui pourrait entreprendre l'apprentissage de React. Entrer en contact avec ces personnes et partager le livre. Cela représente énormément pour moi. Le livre est pensé dans un but de partage et d'ouverture. Il s'améliorera à chaque fois que des personnes le lisent et partagent leur feedback avec moi. J'espère également voir votre feedback, avis ou note! 37 | 38 | Merci beaucoup pour avoir lu the Road to learn React. 39 | 40 | Robin 41 | -------------------------------------------------------------------------------- /manuscript/foreword.md: -------------------------------------------------------------------------------- 1 | # Avant-propos 2 | 3 | The Road to learn React vous apprend les fondamentaux de React. Vous y construirez tout au long une application concrète en pur React sans outillage superflux. Tout depuis l'installation du projet jusqu'au déploiement sur un serveur vous sera expliqué. Dans chaque chapitre, le livre embarque du contenu de lecture supplémentaire référencé et des exercices. Après lecture du livre, vous serez en mesure de construire vos propres React applications. Le contenu est mis à jour par moi, et la communauté. 4 | 5 | Dans the Road to learn React, Je souhaite fournir une fondation avant que vous commencez à plonger à l'intérieur du très large écosystème React. Il a moins d'outillages et moins de gestion d'état externe, mais possède beaucoup d'informations à propos de React. Il explique les concepts généraux, les patrons de conceptions et les meilleurs pratiques au sein d'une application React réelle. 6 | 7 | Vous apprendrez à construire votre propre application React. Elle couvre des fonctionnalités réelles comme la pagination, le cache côté client et les intéractions telle que la recherche et le tri. De plus, tout du long vous ferez une transition de JavaScript ES5 à JavaScript ES6. J'espère que ce livre a su capturer mon enthousiasme pour React et JavaScript et vous aide à bien débuter. 8 | 9 | {pagebreak} 10 | 11 | # A propos de l'auteur 12 | 13 | Robin Wieruch est ingénieur logiciel et web allemand qui est dévoué à apprendre et enseigner la programmation en JavaScript. Après obtention de son diplôme de master d'université en science informatique, il a continué son apprentissage de son propre chef tous les jours. Il a gagné de l'expérience auprès de start-ups, où il a utilisé ardemment JavaScript professionnel et sur son temps libre, lui procura l'opportunité d'enseigner aux autres ces thèmes. 14 | 15 | Pendant quelques années, Robin a étroitement travaillé avec une grande équipe d'ingénieurs dans une entreprise appelé Small Improvements sur une application de grande taille. L'entreprise construite un produit SaaS permettant aux clients de créer une culture de feedback au sein de leur entreprise. Derrière tout çà, l'application fonctionnait avec JavaScript pour le frontend et Java pour le backend. Niveau frontend, la première itération a été écrite en Java avec le Framework Wicket et jQuery. Lorsque la première génération de SPAs devint populaire, l'entreprise migra vers Angular 1.x pour la partie frontend de l'application. Après avoir utiliser Angular pendant plus de 2 ans, il devint clair qu'Angular n'était pas la meilleure solution pour travailler avec l'état intensif des applications. C'est pourquoi l'entreprise entreprit un saut final vers React et Redux qui a permis d'opérer sur une important mise à l'échelle avec succès. 16 | 17 | Durant son passage dans l'entreprise, Robin écrivit régulièrement des articles autour du web développement sur son site personnel. Il reçut de bons retours concernant ses articles qui lui permit d'améliorer son style d'écriture et d'enseignement. Article après article, Robin améliora ses capacités à enseigner aux autres. Son premier article comprenait trop de choses ce qui était assez accablant pour les étudiants, mais il les améliora au fil du temps en se concentrant et en enseignant seulement un sujet. 18 | 19 | De nos jours, Robin est un enseignant auto-entrepreneur. Il consacre tout son temps à voir les étudiants s'épanouir en leur donnant des objectifs clairs avec de courtes boucles de réaction. C'est quelque chose que vous apprendriez au sein d'une entreprise de feedback, n'est ce pas? Mais sans coder soi-même, il ne serait pas possible d'enseigner des sujets. C'est pourquoi il a investit son temps restant dans la programmation. Vous pouvez trouver plus d'informations à propos de Robin et les façons de le supporter et de travailler avec lui sur son [site](https://www.robinwieruch.de/about). 20 | 21 | # Témoignages 22 | 23 | Il y a beaucoup de [témoignages](https://roadtoreact.com/), [notations](https://www.goodreads.com/book/show/37503118-the-road-to-learn-react) et [avis](https://www.amazon.com/dp/B077HJFCQX) à propos du livre qui devrait confirmer sa qualité. J'en suis très satisfait, car j'attendais pas d'aussi importants retours. Si vous appréciez également le livre, j'adorerais également trouver votre avis quelque part. Cela m'aide à diffuser le livre. La suite montre un court extrait de ces avis positifs : 24 | 25 | **[Muhammad Kashif](https://twitter.com/appsdevpk/status/848625244956901376) :** 26 | "The Road to Learn React est un livre unique que je recommande à tous étudiants ou professionnels intéressés dans l'apprentissage des bases de React jusqu'aux niveaux avancées. Il embarque des astuces pertinentes et des techniques dont il est difficile de trouver ailleurs, et est remarquablement complet avec l'usage d'exemples et de références pour illustrer les problèmes, j'ai 17 ans d'expérience dans le développement d'applications desktop et web, et avant la lecture de ce livre j'avais des difficultés dans l'apprentissage de React, mais ce livre fonctionne tel de la magie." 27 | 28 | **[Andre Vargas](https://twitter.com/andrevar66/status/853789166987038720) :** "The Road to Learn React de Robin Wieruch est un livre formidable! La major partie de ce que j'ai appris à propos de React et de l'ES6 est dû à ce livre!" 29 | 30 | **[Nicholas Hunt-Walker, Instructor of Python at a Seattle Coding School](https://twitter.com/nhuntwalker/status/845730837823840256) :** "C'est l'un des livres de développement le plus informatif et bien écrie avec lequel j'ai pu travailler. Une solide introduction à React et l'ES6." 31 | 32 | **[Austin Green](https://twitter.com/AustinGreen/status/845321540627521536) :** "Merci, j'adore le livre. Parfait mélange pour apprendre React, l'ES6 et les concepts de programmation de plus haut niveau." 33 | 34 | **[Nicole Ferguson](https://twitter.com/nicoleffe/status/833488391148822528) :** "J'ai fait le cours Road to Learn React de Robin ce weekend et je me sens coupable d'avoir eu tant d'amusements." 35 | 36 | **[Karan](https://twitter.com/kvss1992/status/889197346344493056) :** "Je viens juste de terminer votre Road to React. Le meilleur livre pour un débutant dans le monde de React et de JS. Avec une élégante exposition à l'ES. Kudos! :)" 37 | 38 | **[Eric Priou](https://twitter.com/erixtekila/status/840875459730657283) :** "The Road to learn React de Robin Wieruch est un must à lire. Épuré et concis pour du React et JavaScript." 39 | 40 | **A Rookie Developer :** "Je viens juste de terminer le livre en tant que développeur rookie, merci pour tout ce travail. Il était facile à suivre et je me sens confiant dans le démarrage d'une nouvelle application en partant de rien dans les jours qui viennent. Le livre était bien meilleur que le tutoriel officiel de React.js que j'ai essayé plus tôt (et que je n'ai pu terminer à cause d'un manque de détail). Les exercices à la fin de chaque section étaient très enrichissants." 41 | 42 | **Student :** "Le meilleur livre pour apprendre ReactJS. Le projet avance avec les concepts que nous venons d'apprendre ce qui aide à saisir le sujet. J'ai trouvé "coder et apprendre' comme la meilleure façon pour maitriser la programmation et ce livre fait exactement cela." 43 | 44 | **[Thomas Lockney](https://www.goodreads.com/review/show/1880673388) :** "Une assez solide introduction à React qui n'a pas la prétention d'être complet. Je souhaitais juste avoir un aperçu pour comprendre de quoi cela parlait et c'est exactement ce que ce livre m'a procuré. Je n'ai pas suivi toutes les petites remarques pour en apprendre plus sur les nouvelles fonctionnalités ES6 j'ai juste oublié ("Je ne dirais pas que cela m'a manqué, Bob."). Mais je suis sûr pour ceux d'entre vous qui ont pris le temps et se sont appliqués à suivre cela, vous pouvez probablement en apprendre bien plus que simplement ce que le livre enseigne." 45 | 46 | {pagebreak} 47 | 48 | # Éducation pour les enfants 49 | 50 | Le livre devrait permettre à tout un chacun d'apprendre React. Cependant, pas tout le monde à la possibilité d'utiliser ces ressources, car pas tout le monde n'a pu apprendre l'anglais en premier lieu. Ainsi je veux utiliser le projet pour supporter les projets qui enseignent aux enfants l'anglais dans les pays en voie de développement. 51 | 52 | * Du 11 au 18 avril 2017, [redistribuer, en apprenant](https://www.robinwieruch.de/giving-back-by-learning-react/) 53 | 54 | {pagebreak} 55 | 56 | # FAQ 57 | 58 | **Comment être tenu à jour?** J'ai deux chaînes ou je partage des nouvelles à propos de mon contenu. Vous pouvez soit [souscrire pour recevoir les mises à jour par email](https://www.getrevue.co/profile/rwieruch) ou me [suivre sur Twitter](https://twitter.com/rwieruch). Indépendamment de la chaîne, mon objectif est de partager uniquement du contenu qualitatif. Vous ne recevrez jamais de spam. Une fois que vous recevez la mise à jour comme quoi le livre a été modifié, vous pouvez télécharger sa nouvelle version. 59 | 60 | **Cela utilise-t-il la dernière version de React?** Le livre reçoit toujours une mise à jour lorsque React fait une mise à jour. Habituellement, les livres sont dépassés assez tôt après leur sortie. Puisque ce livre est autopublié, je peux le mettre à jour quand je le souhaite. 61 | 62 | **Couvre-t-il Redux??** Il ne le couvre pas. Par conséquent, j'ai écrit un second livre. The Road to learn React vous fournit de solide fondations avant de plonger dans des sujets avancés. L'implémentation d'une application échantillon dans le livre montrera que vous n'avez pas besoin de Redux pour construire une application en React. Après que vous ayez lu le livre, vous devrez être capable d'implémenter une application complète sans Redux. Ensuite, vous pouvez lire mon second livre, Taming the State in React, pour apprendre [Redux](https://roadtoreact.com). 63 | 64 | 65 | **Utilise-t-il JavaScript ES6?** Oui. Mais ne vous inquiétez pas. Vous n'aurez pas de problème si vous êtes familier avec JavaScript ES5. Toutes fonctionnalités JavaScript ES6, que je décris lors de ce cheminement pour apprendre React, fera une transition de ES5 à ES6. Toutes les fonctionnalités seront expliquées tout du long. Le livre n'apprend pas seulement React, mais aussi toutes les fonctionnalités JavaScript ES6 utiles pour React. 66 | 67 | **Ajouteras-tu plus de chapitres dans le futur?** Si vous avez acheté l'un des packages étendus qui vous confèrent un accès au code source des projets, à l'ensemble des captures d'écrans ou n'importe quelle autre option, vous devriez les retrouver sur votre [dashboard de cours](https://roadtoreact.com/my-courses). Si vous avez acheté le cours autre part que sur [la plateforme officielle de cours Road to React](https://roadtoreact.com), vous aurez besoin de créer un compte sur la platforme, aller sur la page Admin et à me communiquer l'un des templates d'email. Après quoi je pourrai vous enrôler au sein du cours. Si vous n'avez pas acheté l'un des packages étendus, vous pouvez me communiquer à n'importe quel moment pour mettre à jour votre contenu pour accéder au code source des projets et à l'ensemble des captures d'écrans. 68 | 69 | **Comment puis-je être aidé durant la lecture du livre?** Le livre a un [groupe Slack](https://slack-the-road-to-learn-react.wieruch.com/) pour les personnes qui sont en train de lire le livre. Vous pouvez rejoindre la chaine et être aidé ou aider les autres. Après tout, aider les autres peut permettre d'intérioriser votre apprentissage aussi. S'il n'y a personne pour vous aider, vous pouvez toujours me contacter. 70 | 71 | **Y a-t-il des zones de danger?** Si vous rencontrez des problèmes, s'il vous plaît rejoignez le groupe Slack. De plus, vous pouvez jeter un oeil aux [issues ouvertes sur GitHub](https://github.com/rwieruch/the-road-to-learn-react/issues) concernant le livre. Peut-être votre problème a déjà été mentionné et vous pouvez trouver la solution à son propos. Si votre problème n'est pas mentionné, n'hésitez pas à ouvrir un issue où vous pouvez expliquer votre problème, peut être fournir un screenshot, et quelques détails supplémentaires (ex : page du livre, version de node). Après quoi, j'essaye d'embarquer tous les fixes dans les prochaines éditions du livre. 72 | 73 | **Puis-je aider à l'améliorer?** Oui. Je serai ravi d'entendre vos retours. Vous pouvez simplement ouvrir un issue sur [GitHub](https://github.com/rwieruch/the-road-to-learn-react). Cela peut être encore pour un souhait d'amélioration technique ou encore un mot écrit. Je ne suis pas un anglais natif c'est pour cela que n'importe quelle aide est appréciée. Vous pouvez ouvrir des pull requests sur la page Github également. 74 | 75 | **Y as-t-il une garantie de remboursement?** Oui, il y a une garantie de remboursement à 100% pendant deux mois, si vous estimez que cela ne convient pas. Merci de me contacter pour avoir un remboursement. 76 | 77 | **Comment supporter le projet?** Si vous croyez au contenu que j'ai créé, vous pouvez [me supporter](https://www.robinwieruch.de/about/). De plus, je vous serais reconnaissant si vous prêchez la bonne parole à propos de ce livre après l'avoir lu et apprécié. Enfin, j'adorerai vous avoir comme mon [Patron sur Patreon](https://www.patreon.com/rwieruch). 78 | 79 | **Quelle est ta motivation derrière ce livre?** Je souhaite dire un mot sur ce sujet de manière cohérente. Vous trouvez souvent du contenu en ligne qui ne reçoit aucune mise à jour ou enseigne seulement une petite partie d'un sujet. Lorsque vous apprenez quelques choses de nouveau, les personnes luttent pour trouver du contenu cohérent et des ressources à jour sur lequel apprendre. Je veux vous donner cette expérience d'apprentissage consistant et à jour. De plus, j'espère que je peux supporter les minorités avec mes projets en leur donnant le contenu gratuitement ou en [ayant d'autres impactes](https://www.robinwieruch.de/giving-back-by-learning-react/). Qui plus est, récemment, j'ai trouvé mon chemin en enseignant aux autres la programmation. C'est une activité pleine de sens pour moi que je préfère à la place de n'importe quel métier de 9 à 5 au sein de n'importe quelle entreprise. C'est pourquoi j'espère poursuivre ce chemin dans le futur. 80 | 81 | **Y a-t-il un appel à l'action?** Oui. Je veux que vous preniez un moment pour penser à une personne qui pourrait être intéréssée par l'apprentissage de React. La personne pourrait avoir déjà montré de l'intérêt, peut-être en plein apprentissage de React ou pourrait ne pas encore être consciente de vouloir apprendre React. Entrez en contact avec cette personne et partagez le livre. Cela signifie beaucoup pour moi. Le livre est destiné à être offert aux autres. 82 | 83 | {pagebreak} 84 | 85 | # Change Log 86 | 87 | **Le 10 Janvier 2017 :** 88 | 89 | * [v2 Pull Request](https://github.com/rwieruch/the-road-to-learn-react/pull/18) 90 | * Encore plus abordable pour les débutants 91 | * 37% de contenu supplémentaire 92 | * 30% de contenu amélioré 93 | * 13 chapitres améliorés et nouveaux 94 | * 140 pages de ressources didactiques 95 | * [+ cours interactif du livre sur educative.io](https://www.educative.io/collection/5740745361195008/5676830073815040) 96 | 97 | **Le 8 Mars 2017 :** 98 | 99 | * [v3 Pull Request](https://github.com/rwieruch/the-road-to-learn-react/pull/34) 100 | * 20% de contenu supplémentaire 101 | * 25% de contenu amélioré 102 | * 9 nouveaux chapitres 103 | * 170 pages de ressources didactiques 104 | 105 | **Le 15 Avril 2017 :** 106 | 107 | * Mise à niveau en React 15.5 108 | 109 | **Le 5 Juillet 2017 :** 110 | 111 | * Mise à niveau en node 8.1.3 112 | * Mise à niveau en npm 5.0.4 113 | * Mise à niveau en create-react-app 1.3.3 114 | 115 | **Le 17 Octobre 2017 :** 116 | 117 | * Mise à niveau en node 8.3.0 118 | * Mise à niveau en npm 5.5.1 119 | * Mise à niveau en create-react-app 1.4.1 120 | * Mise à niveau en React 16 121 | * [v4 Pull Request](https://github.com/rwieruch/the-road-to-learn-react/pull/72) 122 | * 15% de contenu supplémentaire 123 | * 15% de contenu amélioré 124 | * 3 nouveaux chapitres (Bindings, Event Handlers, Gestion d'erreur) 125 | * 190+ pages de ressources didactiques 126 | * [+9 projets avec code source](https://roadtoreact.com/course-details?courseId=THE_ROAD_TO_LEARN_REACT) 127 | 128 | **17. February 2018 :** 129 | 130 | * Mise à niveau en node 8.9.4 131 | * Mise à niveau en npm 5.6.0 132 | * Mise à niveau en create-react-app 1.5.1 133 | * [v5 Pull Request](https://github.com/the-road-to-learn-react/the-road-to-learn-react/pull/105) 134 | * plus de chemins d'apprentissage 135 | * contenu de lecture référencé supplémentaire 136 | * 1 nouveau chapitre (Axios à la place de Fetch) 137 | 138 | {pagebreak} 139 | 140 | # Comment le lire? 141 | 142 | Le livre est ma tentative pour enseigner React tandis que vous écrirez une application. C'est un guide pratique pour apprendre React et non un travail de référence autour de React. Vous écrirez une application Hacker News qui interagira avec une API réelle. Parmi plusieurs sujets intéressants, il couvre la gestion de l'état au sein de React, le cache et les interactions (le tri et la recherche). Tout du long vous apprendrez les meilleurs pratiques et patrons de conception de React. 143 | 144 | De plus, le livre vous donne une transition de JavaScript ES5 vers JavaScript ES6. React adopte beaucoup de fonctionnalités JavaScript ES6 et je souhaite vous montrer comment vous pouvez les utiliser. 145 | 146 | En général chaque chapitre du livre repose sur le chapitre précédent. Chaque chapitre vous enseignera quelque chose de nouveau. Ne vous précipitez sur le livre. Vous devez intérioriser chaque étape. Vous pouvez appliquer vos propres implémentations et en lire davantage sur le sujet. Après chaque chapitre je vous donne quelques lectures supplémentaires et implémentations ainsi que de la lecture supplémentaire à propos du sujet. Si vous voulez vraiment apprendre React, Je vous recommande chaudement de lire la documentation supplémentaire et de faire les quelques exercices pratiques. Après que vous ayez lu un chapitre, devenez à l'aise avec les acquis avant de continuer. 147 | 148 | En fin de compte vous aurez une complète application React en production. Je suis très impatient de voir vos résultats, donc s'il vous plaît écrivez-moi lorsque vous avez fini le livre. Le chapitre final du livre vous donnera plusieurs options pour poursuivre votre voyage auprès de React. En général vous trouverez beaucoup de sujets reliés à React sur [mon site web personnel](https://www.robinwieruch.de/). 149 | 150 | Puisque vous lisez le livre, je devine que vous êtes nouveau à React. C'est parfait. À la fin j'espère avoir des retours pour améliorer le contenu pour permettre à tout à chacun d'apprendre React. Vous pouvez avoir un impact direct sur [GitHub](https://github.com/rwieruch/the-road-to-learn-react) ou écrivez-moi sur [Twitter](https://twitter.com/rwieruch). 151 | 152 | {pagebreak} 153 | 154 | # Challenge 155 | 156 | Personnellement, j'hésite pas à prendre la plume pour partager mes apprentissages. C'est comme cela que j'en suis arrivé là où j'en suis. Vous enseignez de façon optimale un sujet dès lors que vous venez juste de l'apprendre par vous-même. Puisqu'enseigné un sujet m'aida dans ma carrière, je veux que vous expérimenter cela. Mais avant tout commencé par la cause de tout cela votre propre apprentissage. Mon challenge pour le livre est le suivant : 157 | Apprendre aux autres ce que vous êtes en train d'apprendre tandis que vous lisez le livre. Quelques jalons sur comment vous pouvez réaliser cela : 158 | 159 | * Écrire un blog post à propos d'un sujet particulier du livre. Je ne dis pas de copier et coller le contenu mais plutôt d'enseigner le sujet à votre manière. Trouver vos propres mots pour expliquer les points; saisir un problème et le résoudre, et même plonger plus profonds dans le sujet en comprenant les moindres détails. Puis enseignez-le dans un article. Vous observerez comment cela comblera vos trous de connaissance et comment cela ouvre des portes pour votre carrière sur le long terme. 160 | 161 | * Si vous êtes actif sur les réseaux sociaux, comprenez et partagez a vos amis quelques astuces que vous avez apprises au cours de la lecture du livre. Par exemple, vous pouvez tweeter un bon tuyau sur Twitter à propos de votre dernière connaissance autour du livre qui pourrait être intéressante à d'autres également. Prenez juste un screenshot du passage du livre ou même mieux : écrivez à votre manière autour de cela. C'est comme cela que vous allez passer du côté de l'apprentissage sans investir trop de temps. 162 | 163 | * Si vous vous sentez confiant vous pouvez enregistrer votre apprentissage, partager votre aventure au travers du livre sur Facebook Live, Youtube Live ou Twitch. Cela permet de rester concentrer et de travailler à votre rythme avec le livre. Même si vous n'avez pas de personne qui suive vos live session, vous pouvez toujours placer la vidéo sur Youtube par la suite. De plus, c'est un moyen de verbaliser vos problèmes et de voir comment les résoudre. 164 | 165 | J'aimerais tellement voir des personnes réaliser ce dernier jalon : s'enregistrer soi-même pendant la lecture de ce livre, implémenter les applications, et organiser les exercices, puis uploader la version finale sur Youtube. Si des parties de l'enregistrement prennent un certain temps, juste couper la vidéo ou utiliser un effet timelapse. Si vous restez coincé et avez besoin de fixer un bug, ne couper pas ces passages mais plutôt les inclure dans la vidéo, car ils sont tellement plein de sens auprès de l'audience qui pourrait rencontrer les mêmes problèmes. Je crois que c'est important d'avoir ces parties dans votre vidéo. Quelques astuces pour la vidéo : 166 | 167 | * Faites-le dans votre langue maternelle, mais aussi en anglais si vous vous sentez à l'aise. 168 | 169 | * Verbaliser vos pensées, expliciter ce que vous êtes en train de faire ou les problèmes que vous rencontrer sur votre chemin. Avoir une vidéo visuelle n'est seulement qu'une partie du challenge, l'autre partie consiste à narrer durant l'implémentation. Cela n'a pas à être parfait. À la place cela doit sembler naturel et non polis comme toutes les autres vidéos d'apprentissage en ligne où personne rencontre de problèmes. 170 | 171 | * Si vous rencontrez des bugs, prennez le temps de comprendre le soucis. Essayer de fixer le problème par vous-même, n'abandonnez pas, et parlez du problème et de comment vous tentez de le résoudre. Cela aide les autres à suivre votre processus de pensé. Comme je l'ai dit précédemment, cela n'a pas de valeur de suivre des vidéos d'apprentissages en ligne dénuée de problèmes. C'est d'une plus grande valeur de voir quelqu'un d'autre en train de fixer un bug dans le code source. 172 | 173 | * Quelques mots à propos de la partie purement technique de l'enregistrement : Vérifier votre audio avant d'enregistrer une longue vidéo. Elle devrait avoir le bon volume et une bonne qualité. Concernant votre éditeur/IDE/terminal, assurez-vous d'augmenter la taille de la police. Peut-être est-il possible de placer le code et le navigateur côte à côte. Dans le cas contraire, faites un plein écran et passer de l'un à l'autre (e.g. MacOS CMD + Tab). 174 | 175 | * Éditer la vidéo vous-même avant de l'uploader sur Youtube. Cela n'a pas à être en haute qualité, mais vous pouvez essayer de rester concis pour votre audience (e.g. mettre de côté les moments de lectures et plutôt résumer les étapes avec vos propres mots). 176 | 177 | À la fin, vous pouvez me joindre pour promouvoir la vidéo. Si la vidéo s'avère bien, je pourrai vouloir l'inclure dans le livre officiellement en tant que contenu supplémentaire. Juste contactez-moi une fois que vous l'avez fini. Après tout, j'espère que vous accepterez ce challenge afin d'améliorer votre expérience d'apprentissage pendant la lecture du livre. En tout cas c'est ce que je vous souhaite. 178 | 179 | {pagebreak} 180 | --------------------------------------------------------------------------------