├── manuscript
├── Book.txt
├── contributor.md
├── deployChapter.md
├── finalwords.md
├── chapter6.md
├── foreword.md
├── chapter5.md
├── chapter4.md
└── chapter1.md
└── README.md
/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/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}
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # The Road to learn React [Livre]
2 |
3 | [](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/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/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 |
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/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 |
--------------------------------------------------------------------------------
/manuscript/chapter5.md:
--------------------------------------------------------------------------------
1 | # React composants avancés
2 |
3 | Le chapitre se concentrera sur l'implémentation de composants React avancés. Vous apprendrez à propos des composants d'ordre supérieur et comment les implémenter. De plus, vous plongerez dans des sujets plus avancés de React et implémenterez des interactions complexes avec ce dernier.
4 |
5 | ## Ref un DOM Element
6 |
7 | Parfois vous aurez besoin d'interagir avec votre noeud de DOM au sein de React. L'attribut `ref` vous donne un accès à un noeud de vos éléments. Habituellement c'est un anti-pattern en React, car vous devez l'utiliser sa manière déclarative pour faire quoi que ce soit ainsi que son flux de données unidirectionnel. Vous avez appris cela lorsque vous avez introduit votre premier champ d'entrée de recherche. Mais il y a certains cas où vous avez besoin d'accéder à un noeud de DOM. La documentation officielle mentionne trois cas :
8 |
9 | * utiliser l'API du DOM (focus, media playback etc.)
10 | * invoquer des animations impératives de noeuds du DOM
11 | * intégrer une librairie tierce qui a besoin de noeuds du DOM (ex : [D3.js](https://d3js.org/))
12 |
13 | Réalisons un exemple avec le composant Search. Lorsque l'application se rend pour la première fois, le champ d'entrée devra être en focus. C'est l'un des cas d'utilisation où vous aurez besoin d'accéder à l'API du DOM. Ce chapitre vous montre comment cela fonctionne, mais puisque c'est ne pas très utile pour l'application en soi, nous omettrons les changements dans le prochain chapitre. Néanmoins vous pouvez les conserver pour votre propre application.
14 |
15 | En général, vous pouvez utiliser l'attribut `ref` à la fois dans les composants fonctionnels stateless et les composants de classe ES6. Dans le cas de la fonctionnalité de focus, vous aurez besoin des méthodes du cycle de vie. C'est pourquoi l'approche est en premier lieu présentée en utilisant l'attribut `ref` avec un composant de classe ES6.
16 |
17 | L'étape initiale consiste à refactoriser le composant fonctionnel stateless en un composant de classe ES6.
18 |
19 | {title="src/App.js",lang=javascript}
20 | ~~~~~~~~
21 | # leanpub-start-insert
22 | class Search extends Component {
23 | render() {
24 | const {
25 | value,
26 | onChange,
27 | onSubmit,
28 | children
29 | } = this.props;
30 |
31 | return (
32 | # leanpub-end-insert
33 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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/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(
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 ``, `