You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/content/2/fr/part2d.md
+5-5Lines changed: 5 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -698,19 +698,19 @@ Le code de l'état actuel de notre application se trouve sur la branche <i>part2
698
698
699
699
<div class="tasks">
700
700
701
-
<h3>Exercices 2.15.-2.18.</h3>
701
+
<h3>Exercices 2.12.-2.15.</h3>
702
702
703
-
<h4>2.15: phonebook, étape7</h4>
703
+
<h4>2.12: phonebook, étape7</h4>
704
704
705
705
Revenons à notre application de répertoire.
706
706
707
707
Actuellement, les numéros ajoutés au répertoire ne sont pas enregistrés sur un serveur principal. Corrigez cette situation.
708
708
709
-
<h4>2.16: phonebook, étape8</h4>
709
+
<h4>2.13: phonebook, étape8</h4>
710
710
711
711
Extrayez le code qui gère la communication avec le backend dans son propre module en suivant l'exemple présenté précédemment dans cette partie du support de cours.
712
712
713
-
<h4>2.17: phonebook étape9</h4>
713
+
<h4>2.14: phonebook étape9</h4>
714
714
715
715
Permettre aux utilisateurs de supprimer des entrées du répertoire. La suppression peut être effectuée via un bouton dédié pour chaque personne dans la liste du répertoire. Vous pouvez confirmer l'action de l'utilisateur en utilisant la méthode [window.confirm](https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm) :
716
716
@@ -729,7 +729,7 @@ const delete = (id) => {
729
729
}
730
730
```
731
731
732
-
<h4>2.18*: phonebook, étape10</h4>
732
+
<h4>2.15*: phonebook, étape10</h4>
733
733
734
734
Modifiez le code de sorte que si un numéro est ajouté à un utilisateur déjà existant, le nouveau numéro remplacera l'ancien numéro. Il est recommandé d'utiliser la méthode HTTP PUT pour mettre à jour le numéro de téléphone.
Copy file name to clipboardExpand all lines: src/content/2/fr/part2e.md
+264-4Lines changed: 264 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -282,15 +282,15 @@ Le code de la version finale de notre application se trouve sur la branche <i>pa
282
282
283
283
<divclass="tasks">
284
284
285
-
<h3>Exercices 2.19.-2.20.</h3>
285
+
<h3>Exercices 2.16.-2.17.</h3>
286
286
287
-
<h4>2.19: phonebook, étape11</h4>
287
+
<h4>2.16: phonebook, étape11</h4>
288
288
289
289
Utilisez l'exemple de [message d'erreur amélioré](/en/part2/adding_styles_to_react_app#improved-error-message) de la partie 2 comme guide pour afficher une notification qui dure quelques secondes après l'exécution d'une opération réussie (une personne est ajoutée ou un nombre est modifié) :
290
290
291
291

292
292
293
-
<h4>2.20*: phonebook, étape12</h4>
293
+
<h4>2.17*: phonebook, étape12</h4>
294
294
295
295
Ouvrez votre application dans deux navigateurs. **Si vous supprimez une personne dans le navigateur 1**, essayer de <i>modifier le numéro de téléphone de la personne</i> dans le navigateur 2, vous obtiendrez le message d'erreur suivant :
296
296
@@ -302,6 +302,266 @@ Corrigez le problème selon l'exemple présenté dans [promises et erreurs](/en/
302
302
303
303
**Note** Même si vous gérez l'exception, le message d'erreur est affiché sur la console.
304
304
305
-
C'était le dernier exercice de cette partie du cours. Il est temps de transmettre votre code à GitHub et de marquer tous vos exercices terminés dans le [système de soumission d'exercices](https://studies.cs.helsinki.fi/stats/courses/fullstackopen).
305
+
</div>
306
+
307
+
<divclass="content">
308
+
309
+
### Quelques remarques importantes
310
+
311
+
À la fin de cette partie, vous trouverez quelques exercices plus difficiles. À ce stade, vous pouvez les ignorer s'ils vous semblent trop complexes. Nous y reviendrons plus tard. Quoi qu'il en soit, ce document mérite d'être lu.
312
+
313
+
Nous avons fait, dans notre application, quelque chose qui masque une source d'erreur très courante.
314
+
315
+
Nous avons initialisé l'etat de _notes_ à partir d'un tableau vide:
316
+
317
+
```js
318
+
constApp= () => {
319
+
const [notes, setNotes] =useState([])
320
+
321
+
// ...
322
+
}
323
+
```
324
+
325
+
C'est une valeur initiale tout à fait naturelle, puisque notes constitue un ensemble, c'est-à-dire qu'il y a de nombreuses notes que l'état va stocker.
326
+
327
+
Si l'état ne devait sauvegarder qu' " une seule chose ", une valeur initiale plus appropriée serait null, ce qui indique qu'il n'y a <i>rien</i> dans l'état au départ. Voyons ce qui se passe si nous utilisons cette valeur initiale :

340
+
341
+
Le message d'erreur indique la raison et l'emplacement de l'erreur. Le code qui a provoqué le problème est le suivant :
342
+
343
+
```js
344
+
// notesToShow gets the value of notes
345
+
constnotesToShow= showAll
346
+
? notes
347
+
:notes.filter(note=>note.important)
348
+
349
+
// ...
350
+
351
+
{notesToShow.map(note=>// highlight-line
352
+
<Note key={note.id} note={note} />
353
+
)}
354
+
```
355
+
356
+
Le message d'erreur est:
357
+
358
+
```bash
359
+
Cannot read properties of null (reading 'map')
360
+
```
361
+
362
+
La variable _notesToShow_ est d'abord assigné à la valeur de l'état _notes_ puis le code tente d'appeler la méthode _map_ sur un object inexistant, c'est à dire sur _null_.
363
+
364
+
Pourquoi ?
365
+
366
+
Le hook d'effet(useEffect) utilise la fonction _setNotes_ pour affecter à _notes_ les données renvoyées par le back-end
367
+
368
+
```js
369
+
useEffect(() => {
370
+
noteService
371
+
.getAll()
372
+
.then(initialNotes=> {
373
+
setNotes(initialNotes) // highlight-line
374
+
})
375
+
}, [])
376
+
```
377
+
378
+
Cependant, le problème est que le hook d'effet n'est exécuté qu'<i>après le premier rendu</i>.
Lors du premier rendu, le code suivant est exécuté :
389
+
390
+
```js
391
+
notesToShow = notes
392
+
393
+
// ...
394
+
395
+
notesToShow.map(note=>...)
396
+
```
397
+
398
+
et cela fait planter l'application, car on ne peut pas appeler la méthode _map_ sur une valeur _null_.
399
+
400
+
En initialisant _notes_ avec un tableau vide, il n'y a pas d'erreur puisqu'il est permis d'utiliser _map_ sur un tableau vide
401
+
402
+
Ainsi, l'initialisation de l'état a "masqué" le problème lié au fait que les données ne sont pas encore récupérées depuis le backend
403
+
404
+
une autre manière de contourner le problème aurait été d'utiliser un <i>rendu conditionnel</i> et de retourner null tant que l'état du composant n'est pas correctement initialisé :
Donc, lors du premier rendu, rien n'est affiché. Lorsque les notes arrivent du backend, l'effet utilise la fonction _setNotes_ our mettre à jour la valeur de l'état _notes_. Cela provoque un nouveau rendu du composant, et lors de ce second rendu, les notes sont affichées à l'écran.
431
+
432
+
Cette méthode basée sur le rendu conditionnel convient dans les cas où il est impossible de définir l'état de façon à permettre un rendu initial.
433
+
434
+
L'autre point auquel il nous faut encore jeter un œil est le second paramètre de useEffect:
435
+
436
+
```js
437
+
useEffect(() => {
438
+
noteService
439
+
.getAll()
440
+
.then(initialNotes=> {
441
+
setNotes(initialNotes)
442
+
})
443
+
}, []) // highlight-line
444
+
```
445
+
446
+
Le second paramètre de <em>useEffect</em> sert à [spécifier la fréquence d'exécution de l'effet](https://react.dev/reference/react/useEffect#parameters). Le principe est que l'effet s'exécute systématiquement après le premier rendu du composant <i>et</i> à chaque fois que la valeur de ce second paramètre change.
447
+
448
+
Si ce second paramètre est un tableau vide <em>[]</em>, son contenu ne change jamais et l'effet n'est exécuté qu'après le premier rendu du composant. C'est exactement ce que l'on souhaite lorsqu'on initialise l'état de l'application depuis le serveur.
449
+
450
+
Cependant, il existe des situations où l'on veut exécuter cet effet à d'autres moments, par exemple lorsque l'état du composant change de manière particulière.
451
+
452
+
Considérons l'exemple d'une application simple pour interroger les taux de change via [l'Api de taux de change](https://www.exchangerate-api.com/):
453
+
454
+
```js
455
+
import { useState, useEffect } from'react'
456
+
importaxiosfrom'axios'
457
+
458
+
constApp= () => {
459
+
const [value, setValue] =useState('')
460
+
const [rates, setRates] =useState({})
461
+
const [currency, setCurrency] =useState(null)
462
+
463
+
useEffect(() => {
464
+
console.log('effect run, currency is now', currency)
L'interface utilisateur de l'application comporte un formulaire dont le champ de saisie reçoit le code de la devise désirée. Si la devise existe, l'application affiche ses taux de change par rapport aux autres monnaies :
503
+
504
+

505
+
506
+
Lorsque l’on appuie sur le bouton, l’application stocke la devise saisie dans l’état _currency_.
507
+
508
+
Dès que la valeur de _currency_ change, l’application récupère ses taux de change depuis l’API dans la fonction d’effet :
509
+
510
+
```js
511
+
constApp= () => {
512
+
// ...
513
+
const [currency, setCurrency] =useState(null)
514
+
515
+
useEffect(() => {
516
+
console.log('effect run, currency is now', currency)
Le hook useEffect prend désormais _[currency]_ comme second paramètre. La fonction d’effet s’exécute donc après le premier rendu et <i>à chaque fois</i> que la valeur de ce second paramètre _[currency]_ change. Autrement dit, lorsque l’état _currency_ reçoit une nouvelle valeur, le contenu du tableau est mis à jour et la fonction d’effet est relancée.
533
+
534
+
Il est normal de choisir _null_ comme valeur initiae pour la variable _currency_, puisque _currency_ ne stocke qu'un seul élément. la valeur _null_ indique qu’il n’y a encore rien dans l’état, et il est très simple, à l’aide d’un if, de vérifier si la variable a reçu une valeur. L’effet comporte donc la condition suivante :
535
+
536
+
```js
537
+
if (currency) {
538
+
// exchange rates are fetched
539
+
}
540
+
```
541
+
542
+
ce qui empêche de requêter les taux de change juste après le premier rendu lorsque la variable _currency_ a encore sa valeur initiale, c’est-à-dire _null_.
543
+
544
+
Ainsi, si l’utilisateur saisit par exemple <i>eur</i> dans le champ de recherche, l’application utilise Axios pour effectuer une requête HTTP GET vers l’adresse <https://open.er-api.com/v6/latest/eur> et stocke la réponse dans l’état _rates_.
545
+
546
+
Lorsque l’utilisateur saisit ensuite une autre valeur dans le champ de recherche, par exemple <i>usd</i>, la fonction d’effet est de nouveau exécutée et les taux de change de la nouvelle devise sont récupérés depuis l’API.
547
+
548
+
La méthode présentée ici pour effectuer les requêtes API peut sembler un peu lourde. Cette application particulière aurait pu être réalisée entièrement sans utiliser useEffect en effectuant les requêtes directement dans le gestionnaire de soumission du formulaire :
Cependant, il existe des situations où cette technique ne fonctionnerait pas. Par exemple, vous <i>pourriez</i> rencontrer un tel cas dans l’exercice 2.20 où l’utilisation de _useEffect_ pourrait apporter une solution. Notez que cela dépend beaucoup de l’approche choisie ; par exemple, la solution modèle n’utilise pas toujours cette astuce.
0 commit comments