diff --git a/src/content/learn/choosing-the-state-structure.md b/src/content/learn/choosing-the-state-structure.md
index b1478324e..4b3204b16 100644
--- a/src/content/learn/choosing-the-state-structure.md
+++ b/src/content/learn/choosing-the-state-structure.md
@@ -1,53 +1,53 @@
---
-title: Choosing the State Structure
+title: Choisir la structure de l'état
---
-Structuring state well can make a difference between a component that is pleasant to modify and debug, and one that is a constant source of bugs. Here are some tips you should consider when structuring state.
+Bien structurer l’état peut faire toute la différence entre un composant agréable à modifier et déboguer, et un composant qui est une source constante de bugs. Voici des conseils que vous devriez prendre en compte pour structurer vos états.
-* When to use a single vs multiple state variables
-* What to avoid when organizing state
-* How to fix common issues with the state structure
+* Quand utiliser une vs. plusieurs variables d'état
+* Les pièges à éviter en organisant l’état
+* Comment résoudre les problèmes courants de structure de l’état
-## Principles for structuring state {/*principles-for-structuring-state*/}
+## Principes de structuration d’état {/*principles-for-structuring-state*/}
-When you write a component that holds some state, you'll have to make choices about how many state variables to use and what the shape of their data should be. While it's possible to write correct programs even with a suboptimal state structure, there are a few principles that can guide you to make better choices:
+Quand vous créez un composant qui contient des états, vous devez faire des choix sur le nombre de variables d’état à utiliser et la forme de leurs données. Même s'il est possible d’écrire des programmes corrects avec une structure d’état sous-optimale, il y a quelques principes qui peuvent vous guider pour faire de meilleurs choix :
-1. **Group related state.** If you always update two or more state variables at the same time, consider merging them into a single state variable.
-2. **Avoid contradictions in state.** When the state is structured in a way that several pieces of state may contradict and "disagree" with each other, you leave room for mistakes. Try to avoid this.
-3. **Avoid redundant state.** If you can calculate some information from the component's props or its existing state variables during rendering, you should not put that information into that component's state.
-4. **Avoid duplication in state.** When the same data is duplicated between multiple state variables, or within nested objects, it is difficult to keep them in sync. Reduce duplication when you can.
-5. **Avoid deeply nested state.** Deeply hierarchical state is not very convenient to update. When possible, prefer to structure state in a flat way.
+1. **Regroupez les états associés.** Si vous mettez tout le temps à jour plusieurs variables d’état à la fois, essayez de les fusionner en une seule variable d’état.
+2. **Évitez les contradictions dans l’état.** Quand l’état est structuré de sorte que plusieurs parties d’état puissent être contradictoires, des erreurs peuvent survenir. Essayez d’éviter ça.
+3. **Évitez les états redondants.** Si vous pouvez calculer des informations à partir des props du composant ou de ses variables d'état existantes pendant le rendu, vous ne devriez pas mettre ces informations dans un état du composant.
+4. **Évitez la duplication d’états.** Lorsque la même donnée est dupliquée entre plusieurs variables d’état ou dans des objets imbriqués, il devient difficile de les garder synchronisées. Réduisez la duplication dans toute la mesure du possible.
+5. **Évitez les états fortement imbriqués.** Un état fortement hiérarchisé n’est pas très pratique à mettre à jour. Quand c’est possible, priorisez une structure d'état plate.
-The goal behind these principles is to *make state easy to update without introducing mistakes*. Removing redundant and duplicate data from state helps ensure that all its pieces stay in sync. This is similar to how a database engineer might want to ["normalize" the database structure](https://docs.microsoft.com/en-us/office/troubleshoot/access/database-normalization-description) to reduce the chance of bugs. To paraphrase Albert Einstein, **"Make your state as simple as it can be--but no simpler."**
+Ces principes visent à *rendre l’état simple à actualiser sans créer d’erreurs*. Retirer les données redondantes et dupliquées de l’état aide à s’assurer que toutes ses parties restent synchronisées. C’est un peu comme un ingénieur de bases de données qui souhaite [« normaliser » la structure de la base de données](https://learn.microsoft.com/fr-fr/office/troubleshoot/access/database-normalization-description) pour réduire les risques de bugs. Pour paraphraser Albert Einstein : **« Faites que votre état soit le plus simple possible — mais pas plus simple. »**
-Now let's see how these principles apply in action.
+Maintenant voyons comment ces principes s’appliquent concrètement.
-## Group related state {/*group-related-state*/}
+## Regrouper les états associés {/*group-related-state*/}
-You might sometimes be unsure between using a single or multiple state variables.
+Vous hésitez peut-être parfois entre utiliser une ou plusieurs variables d’état.
-Should you do this?
+Devriez-vous faire ça ?
```js
const [x, setX] = useState(0);
const [y, setY] = useState(0);
```
-Or this?
+Ou ça ?
```js
const [position, setPosition] = useState({ x: 0, y: 0 });
```
-Technically, you can use either of these approaches. But **if some two state variables always change together, it might be a good idea to unify them into a single state variable.** Then you won't forget to always keep them in sync, like in this example where moving the cursor updates both coordinates of the red dot:
+Techniquement, les deux approches sont possibles. Mais **si deux variables d’état changent toujours ensemble, ce serait une bonne idée de les réunir en une seule variable d’état**. Vous n’oublierez ainsi pas ensuite de les garder synchronisées, comme dans cet exemple où les mouvements du curseur mettent à jour les deux coordonnées du point rouge.
@@ -93,17 +93,17 @@ body { margin: 0; padding: 0; height: 250px; }
-Another case where you'll group data into an object or an array is when you don't know how many pieces of state you'll need. For example, it's helpful when you have a form where the user can add custom fields.
+Une autre situation dans laquelle vous pouvez regrouper des données dans un objet ou une liste, c'est lorsque vous ne savez pas à l'avance de combien d'éléments d'état vous aurez besoin. Par exemple, c’est utile pour un formulaire dans lequel l’utilisateur peut ajouter des champs personnalisés.
-If your state variable is an object, remember that [you can't update only one field in it](/learn/updating-objects-in-state) without explicitly copying the other fields. For example, you can't do `setPosition({ x: 100 })` in the above example because it would not have the `y` property at all! Instead, if you wanted to set `x` alone, you would either do `setPosition({ ...position, x: 100 })`, or split them into two state variables and do `setX(100)`.
+Si votre variable d’état est un objet, souvenez-vous que [vous ne pouvez pas mettre à jour qu’un seul champ](/learn/updating-objects-in-state) sans explicitement copier les autres champs. Par exemple, vous ne pouvez pas faire `setPosition({ x: 100 })` dans l’exemple ci-dessus car il n’y aurait plus du tout la propriété `y` ! Au lieu de ça, si vous vouliez définir `x` tout seul, soit vous feriez `setPosition({ ...position, x: 100 })`, soit vous découperiez l'information en deux variables d’état et feriez `setX(100)`.
-## Avoid contradictions in state {/*avoid-contradictions-in-state*/}
+## Évitez les contradictions dans l’état {/*avoid-contradictions-in-state*/}
-Here is a hotel feedback form with `isSending` and `isSent` state variables:
+Voici un questionnaire de satisfaction d’hôtel avec les variables d’état `isSending` et `isSent` :
@@ -124,12 +124,12 @@ export default function FeedbackForm() {
}
if (isSent) {
- return
Thanks for feedback!
+ return
Merci pour votre retour !
}
return (
);
}
-// Pretend to send a message.
+// Prétend envoyer un message.
function sendMessage(text) {
return new Promise(resolve => {
setTimeout(resolve, 2000);
@@ -157,9 +157,9 @@ function sendMessage(text) {
-While this code works, it leaves the door open for "impossible" states. For example, if you forget to call `setIsSent` and `setIsSending` together, you may end up in a situation where both `isSending` and `isSent` are `true` at the same time. The more complex your component is, the harder it is to understand what happened.
+Même si ce code marche, il laisse la place à des états « impossibles ». Par exemple, si vous oubliez d’appeler `setIsSent` et `setIsSending` ensemble, vous pouvez finir dans une situation où les deux variables `isSending` et `isSent` sont à `true` au même moment. Plus votre composant est complexe, plus il est dur de comprendre ce qu’il s’est passé.
-**Since `isSending` and `isSent` should never be `true` at the same time, it is better to replace them with one `status` state variable that may take one of *three* valid states:** `'typing'` (initial), `'sending'`, and `'sent'`:
+**Comme `isSending` et `isSent` ne doivent jamais être à `true` au même moment, il est préférable de les remplacer par une variable d’état `status` qui peut prendre l’un des *trois* états valides :** `'typing'` (initial), `'sending'`, et `'sent'` :
@@ -181,12 +181,12 @@ export default function FeedbackForm() {
const isSent = status === 'sent';
if (isSent) {
- return
Thanks for feedback!
+ return
Merci pour votre retour !
}
return (
);
}
-// Pretend to send a message.
+// Prétend envoyer un message.
function sendMessage(text) {
return new Promise(resolve => {
setTimeout(resolve, 2000);
@@ -214,20 +214,20 @@ function sendMessage(text) {
-You can still declare some constants for readability:
+Vous pouvez toujours déclarer quelques constantes pour plus de lisibilité :
```js
const isSending = status === 'sending';
const isSent = status === 'sent';
```
-But they're not state variables, so you don't need to worry about them getting out of sync with each other.
+Mais ce ne sont pas des variables d’état, vous n'avez donc pas à vous soucier de leur désynchronisation.
-## Avoid redundant state {/*avoid-redundant-state*/}
+## Évitez les états redondants {/*avoid-redundant-state*/}
-If you can calculate some information from the component's props or its existing state variables during rendering, you **should not** put that information into that component's state.
+Si vous pouvez calculer certaines informations depuis les props d’un composant ou une de ses variables d’état existantes pendant le rendu, vous ne **devez pas** mettre ces informations dans l’état du composant
-For example, take this form. It works, but can you find any redundant state in it?
+Par exemple, prenez ce formulaire. Il marche, mais pouvez-vous y trouver un état redondant ?
@@ -251,23 +251,23 @@ export default function Form() {
return (
<>
-
Let’s check you in
+
Enregistrons votre arrivée
- Your ticket will be issued to: {fullName}
+ Votre billet sera au nom de : {fullName}
>
);
@@ -280,9 +280,9 @@ label { display: block; margin-bottom: 5px; }
-This form has three state variables: `firstName`, `lastName`, and `fullName`. However, `fullName` is redundant. **You can always calculate `fullName` from `firstName` and `lastName` during render, so remove it from state.**
+Ce formulaire possède trois variables d’état : `firstName`, `lastName` et `fullName`. Cependant, `fullName` est redondant. **Vous pouvez toujours calculer `fullName` depuis `firstName` et `lastName` pendant le rendu, donc retirez-le de l’état.**
-This is how you can do it:
+Voici comment vous pouvez faire :
@@ -305,23 +305,23 @@ export default function Form() {
return (
<>
-
Let’s check you in
+
Enregistrons votre arrivée
- Your ticket will be issued to: {fullName}
+ Votre billet sera au nom de : {fullName}
>
);
@@ -334,50 +334,53 @@ label { display: block; margin-bottom: 5px; }
-Here, `fullName` is *not* a state variable. Instead, it's calculated during render:
+Ici, `fullName` n’est *pas* une variable d’état. Elle est plutôt évaluée pendant le rendu :
```js
const fullName = firstName + ' ' + lastName;
```
-As a result, the change handlers don't need to do anything special to update it. When you call `setFirstName` or `setLastName`, you trigger a re-render, and then the next `fullName` will be calculated from the fresh data.
+Par conséquent, les gestionnaires de changement n’auront rien à faire pour le mettre à jour. Lorsque vous appelez `setFirstName` ou `setLastName`, vous déclenchez un nouveau rendu, et le prochain `fullName` sera calculé à partir des nouvelles données.
-#### Don't mirror props in state {/*don-t-mirror-props-in-state*/}
+#### Ne dupliquez pas les props dans l’état {/*don-t-mirror-props-in-state*/}
-A common example of redundant state is code like this:
+Un exemple commun d’état redondant recourt à ce genre de code :
```js
function Message({ messageColor }) {
const [color, setColor] = useState(messageColor);
+}
```
-Here, a `color` state variable is initialized to the `messageColor` prop. The problem is that **if the parent component passes a different value of `messageColor` later (for example, `'red'` instead of `'blue'`), the `color` *state variable* would not be updated!** The state is only initialized during the first render.
+Ici, la prop `messageColor` est passée comme valeur initiale de la variable d’état `color`. Le problème est que **si le composant parent transmet une valeur différente dans `messageColor` plus tard (par exemple, `'red'` au lieu de `'blue'`), la variable d’état `color` ne sera pas mise à jour** ! L’état est seulement initialisé lors du rendu initial.
-This is why "mirroring" some prop in a state variable can lead to confusion. Instead, use the `messageColor` prop directly in your code. If you want to give it a shorter name, use a constant:
+C’est pourquoi la "duplication" de certaines props dans des variables d’état peut être déroutante. Utilisez de préférence directement la prop `messageColor` dans votre code. Si vous voulez lui donner un nom plus court, utilisez une constante :
```js
function Message({ messageColor }) {
const color = messageColor;
+}
```
-This way it won't get out of sync with the prop passed from the parent component.
+De cette manière, le composant ne sera pas désynchronisé avec la prop qui lui aura été transmise par le composant parent.
-"Mirroring" props into state only makes sense when you *want* to ignore all updates for a specific prop. By convention, start the prop name with `initial` or `default` to clarify that its new values are ignored:
+« Dupliquer » les props dans l’état n'est pertinent que lorsque vous *voulez* ignorer toutes les mises à jour d’une certaine prop. Par convention, ajoutez `initial` ou `default` au début du nom de la prop pour préciser que ses nouvelles valeurs seront ignorées :
```js
function Message({ initialColor }) {
- // The `color` state variable holds the *first* value of `initialColor`.
- // Further changes to the `initialColor` prop are ignored.
+ // La variable d’état `color` contient la *première* valeur de `initialColor`.
+ // Les changements ultérieurs de la prop `initialColor` seront ignorés.
const [color, setColor] = useState(initialColor);
+}
```
-## Avoid duplication in state {/*avoid-duplication-in-state*/}
+## Évitez la duplication d’états {/*avoid-duplication-in-state*/}
-This menu list component lets you choose a single travel snack out of several:
+Ce composant de carte de menu vous permet de choisir un seul en-cas de voyage parmi plusieurs :
@@ -385,9 +388,9 @@ This menu list component lets you choose a single travel snack out of several:
import { useState } from 'react';
const initialItems = [
- { title: 'pretzels', id: 0 },
- { title: 'crispy seaweed', id: 1 },
- { title: 'granola bar', id: 2 },
+ { title: 'bretzels', id: 0 },
+ { title: 'algues croustillantes', id: 1 },
+ { title: 'paquet de princes', id: 2 },
];
export default function Menu() {
@@ -398,7 +401,7 @@ export default function Menu() {
return (
<>
-
>
);
}
@@ -422,9 +425,9 @@ button { margin-top: 10px; }
-Currently, it stores the selected item as an object in the `selectedItem` state variable. However, this is not great: **the contents of the `selectedItem` is the same object as one of the items inside the `items` list.** This means that the information about the item itself is duplicated in two places.
+À ce stade, il stocke l’élément selectionné en tant qu’objet dans la variable d’état `selectedItem`. Cependant, ce n’est pas optimal : **le contenu de `selectedItem` est le même objet que l’un des éléments de la liste `items`.** Ça signifie que les informations relatives à l’élément sont dupliquées à deux endroits.
-Why is this a problem? Let's make each item editable:
+Pourquoi est-ce un problème ? Rendons chaque objet modifiable :
@@ -432,9 +435,9 @@ Why is this a problem? Let's make each item editable:
import { useState } from 'react';
const initialItems = [
- { title: 'pretzels', id: 0 },
- { title: 'crispy seaweed', id: 1 },
- { title: 'granola bar', id: 2 },
+ { title: 'bretzels', id: 0 },
+ { title: 'algues croustillantes', id: 1 },
+ { title: 'paquet de princes', id: 2 },
];
export default function Menu() {
@@ -458,7 +461,7 @@ export default function Menu() {
return (
<>
-
>
);
}
@@ -487,9 +490,9 @@ button { margin-top: 10px; }
-Notice how if you first click "Choose" on an item and *then* edit it, **the input updates but the label at the bottom does not reflect the edits.** This is because you have duplicated state, and you forgot to update `selectedItem`.
+Remarquez que si vous cliquez d’abord sur « Choisissez » un élément *puis* que vous le modifiez, **le champ se met à jour, mais le libellé en bas reste inchangé**. C’est parce que vous avez dupliqué l’état, et que vous avez oublié de mettre à jour `selectedItem`.
-Although you could update `selectedItem` too, an easier fix is to remove duplication. In this example, instead of a `selectedItem` object (which creates a duplication with objects inside `items`), you hold the `selectedId` in state, and *then* get the `selectedItem` by searching the `items` array for an item with that ID:
+Même si vous pourriez également mettre à jour `selectedItem`, une solution plus simple consiste à supprimer la duplication. Dans cet exemple, au lieu d’un objet `selectedItem` (ce qui crée une duplication des éléments dans `items`), vous gardez le `selectedId` dans l’état, *puis* obtenez le `selectedItem` en cherchant dans la liste `items` un élément avec cet ID :
@@ -497,9 +500,9 @@ Although you could update `selectedItem` too, an easier fix is to remove duplica
import { useState } from 'react';
const initialItems = [
- { title: 'pretzels', id: 0 },
- { title: 'crispy seaweed', id: 1 },
- { title: 'granola bar', id: 2 },
+ { title: 'bretzels', id: 0 },
+ { title: 'algues croustillantes', id: 1 },
+ { title: 'paquet de princes', id: 2 },
];
export default function Menu() {
@@ -525,7 +528,7 @@ export default function Menu() {
return (
<>
-
>
);
}
@@ -554,25 +557,26 @@ button { margin-top: 10px; }
-(Alternatively, you may hold the selected index in state.)
+(Vous pouvez également garder l’index sélectionné dans l’état.)
-The state used to be duplicated like this:
+L’état était dupliqué de cette façon :
* `items = [{ id: 0, title: 'pretzels'}, ...]`
* `selectedItem = {id: 0, title: 'pretzels'}`
-But after the change it's like this:
+Mais après nos changements, il a la structure suivante :
* `items = [{ id: 0, title: 'pretzels'}, ...]`
* `selectedId = 0`
-The duplication is gone, and you only keep the essential state!
+La duplication a disparu, et vous ne conservez que l’état essentiel !
-Now if you edit the *selected* item, the message below will update immediately. This is because `setItems` triggers a re-render, and `items.find(...)` would find the item with the updated title. You didn't need to hold *the selected item* in state, because only the *selected ID* is essential. The rest could be calculated during render.
+Maintenant si vous modifiez l’élément *sélectionné*, le message en dessous sera mis à jour immédiatement. C’est parce que `setItems` déclenche un nouveau rendu, et `items.find(...)` trouve l’élément dont le titre a été mis à jour. Il n’est pas nécessaire de conserver *l’objet sélectionné* dans l’état, car seul l’*ID sélectionné* est essentiel. Le reste peut être calculé lors du rendu.
-## Avoid deeply nested state {/*avoid-deeply-nested-state*/}
+## Évitez les états fortement imbriqués {/*avoid-deeply-nested-state*/}
-Imagine a travel plan consisting of planets, continents, and countries. You might be tempted to structure its state using nested objects and arrays, like in this example:
+
+Imaginez un plan de voyage composé de planètes, de continents et de pays. Vous pourriez être tenté·e de structurer son état à l’aide de listes et d’objets imbriqués, comme dans cet exemple :
@@ -601,7 +605,7 @@ export default function TravelPlan() {
const planets = plan.childPlaces;
return (
<>
-
Places to visit
+
Lieux à visiter
{planets.map(place => (
@@ -618,17 +622,17 @@ export const initialTravelPlan = {
title: '(Root)',
childPlaces: [{
id: 1,
- title: 'Earth',
+ title: 'Terre',
childPlaces: [{
id: 2,
- title: 'Africa',
+ title: 'Afrique',
childPlaces: [{
id: 3,
title: 'Botswana',
childPlaces: []
}, {
id: 4,
- title: 'Egypt',
+ title: 'Egypte',
childPlaces: []
}, {
id: 5,
@@ -640,31 +644,31 @@ export const initialTravelPlan = {
childPlaces: []
}, {
id: 7,
- title: 'Morocco',
+ title: 'Maroc',
childPlaces: []
}, {
id: 8,
- title: 'Nigeria',
+ title: 'Nigéria',
childPlaces: []
}, {
id: 9,
- title: 'South Africa',
+ title: 'Afrique du Sud',
childPlaces: []
}]
}, {
id: 10,
- title: 'Americas',
+ title: 'Amérique',
childPlaces: [{
id: 11,
- title: 'Argentina',
+ title: 'Argentine',
childPlaces: []
}, {
id: 12,
- title: 'Brazil',
+ title: 'Brésil',
childPlaces: []
}, {
id: 13,
- title: 'Barbados',
+ title: 'Barbade',
childPlaces: []
}, {
id: 14,
@@ -672,16 +676,15 @@ export const initialTravelPlan = {
childPlaces: []
}, {
id: 15,
- title: 'Jamaica',
+ title: 'Jamaïque',
childPlaces: []
}, {
id: 16,
- title: 'Mexico',
+ title: 'Mexique',
childPlaces: []
}, {
id: 17,
- title: 'Trinidad and Tobago',
- childPlaces: []
+ title: 'Trinité-et-Tobté-et-childPlaces: []
}, {
id: 18,
title: 'Venezuela',
@@ -689,10 +692,10 @@ export const initialTravelPlan = {
}]
}, {
id: 19,
- title: 'Asia',
+ title: 'Asie',
childPlaces: [{
id: 20,
- title: 'China',
+ title: 'Chine',
childPlaces: []
}, {
id: 21,
@@ -700,19 +703,19 @@ export const initialTravelPlan = {
childPlaces: []
}, {
id: 22,
- title: 'India',
+ title: 'Inde',
childPlaces: []
}, {
id: 23,
- title: 'Singapore',
+ title: 'Singapour',
childPlaces: []
}, {
id: 24,
- title: 'South Korea',
+ title: 'Corée du Sud',
childPlaces: []
}, {
id: 25,
- title: 'Thailand',
+ title: 'Thaïlande',
childPlaces: []
}, {
id: 26,
@@ -724,7 +727,7 @@ export const initialTravelPlan = {
title: 'Europe',
childPlaces: [{
id: 28,
- title: 'Croatia',
+ title: 'Croatie',
childPlaces: [],
}, {
id: 29,
@@ -732,11 +735,11 @@ export const initialTravelPlan = {
childPlaces: [],
}, {
id: 30,
- title: 'Germany',
+ title: 'Allemagne',
childPlaces: [],
}, {
id: 31,
- title: 'Italy',
+ title: 'Italie',
childPlaces: [],
}, {
id: 32,
@@ -744,39 +747,39 @@ export const initialTravelPlan = {
childPlaces: [],
}, {
id: 33,
- title: 'Spain',
+ title: 'Espagne',
childPlaces: [],
}, {
id: 34,
- title: 'Turkey',
+ title: 'Turquie',
childPlaces: [],
}]
}, {
id: 35,
- title: 'Oceania',
+ title: 'Océanie',
childPlaces: [{
id: 36,
- title: 'Australia',
+ title: 'Australie',
childPlaces: [],
}, {
id: 37,
- title: 'Bora Bora (French Polynesia)',
+ title: 'Bora Bora (Polynésie Française)',
childPlaces: [],
}, {
id: 38,
- title: 'Easter Island (Chile)',
+ title: 'Île de Pâques (Chili)',
childPlaces: [],
}, {
id: 39,
- title: 'Fiji',
+ title: 'Fidji',
childPlaces: [],
}, {
id: 40,
- title: 'Hawaii (the USA)',
+ title: 'Hawaï (USA)',
childPlaces: [],
}, {
id: 41,
- title: 'New Zealand',
+ title: 'Nouvelle Zélande',
childPlaces: [],
}, {
id: 42,
@@ -786,7 +789,7 @@ export const initialTravelPlan = {
}]
}, {
id: 43,
- title: 'Moon',
+ title: 'Lune',
childPlaces: [{
id: 44,
title: 'Rheita',
@@ -810,7 +813,7 @@ export const initialTravelPlan = {
}, {
id: 49,
title: 'Green Hill',
- childPlaces: []
+ childPlaces: []
}]
}]
};
@@ -818,11 +821,11 @@ export const initialTravelPlan = {
-Now let's say you want to add a button to delete a place you've already visited. How would you go about it? [Updating nested state](/learn/updating-objects-in-state#updating-a-nested-object) involves making copies of objects all the way up from the part that changed. Deleting a deeply nested place would involve copying its entire parent place chain. Such code can be very verbose.
+Imaginons maintenant que vous souhaitiez ajouter un bouton pour supprimer un lieu que vous avez déjà visité. Comment procéder ? [La mise à jour d’un état imbriqué](/learn/updating-objects-in-state#updating-a-nested-object) implique de faire des copies des objets en remontant depuis la partie qui a changé. Supprimer un lieu profondément imbriqué consisterait à copier tous les niveaux supérieurs. Un tel code peut être très long.
-**If the state is too nested to update easily, consider making it "flat".** Here is one way you can restructure this data. Instead of a tree-like structure where each `place` has an array of *its child places*, you can have each place hold an array of *its child place IDs*. Then store a mapping from each place ID to the corresponding place.
+**Si l’état est trop imbriqué pour être mis à jour facilement, envisagez de « l’aplatir ».** Voici une façon de restructurer ces données. Au lieu d’une structure arborescente où chaque *lieu* possède une liste de *ses lieux enfants*, chaque lieu peut posséder une liste des *ID de ses lieux enfants*. Vous pouvez alors stocker une table de correspondance entre chaque ID de lieu et le lieu correspondant.
-This data restructuring might remind you of seeing a database table:
+Cette restructuration des données pourrait vous rappeler une table de base de données :
@@ -857,7 +860,7 @@ export default function TravelPlan() {
const planetIds = root.childIds;
return (
<>
-
Places to visit
+
Lieux à visiter
{planetIds.map(id => (
-**Now that the state is "flat" (also known as "normalized"), updating nested items becomes easier.**
+**Maintenant que l’état est « plat » (on pourrait aussi dire « normalisé »), mettre à jour des éléments imbriqués devient plus simple.**
-In order to remove a place now, you only need to update two levels of state:
+Désormais, afin d’enlever un lieu, vous n'avez besoin de mettre à jour que deux niveaux d’état :
-- The updated version of its *parent* place should exclude the removed ID from its `childIds` array.
-- The updated version of the root "table" object should include the updated version of the parent place.
+- La version à jour de son lieu *parent* devrait exclure l’ID supprimé de sa liste `childIds`.
+- La version à jour de la « table » racine d’objets doit inclure la version à jour du lieu parent.
-Here is an example of how you could go about it:
+Voici un exemple de comment vous pourriez procéder :
@@ -1149,17 +1152,17 @@ export default function TravelPlan() {
function handleComplete(parentId, childId) {
const parent = plan[parentId];
- // Create a new version of the parent place
- // that doesn't include this child ID.
+ // Créer une nouvelle version du lieu parent
+ // qui n’inclut pas l’ID de son enfant.
const nextParent = {
...parent,
childIds: parent.childIds
.filter(id => id !== childId)
};
- // Update the root state object...
+ // Mettre à jour l’état de l’objet d’origine...
setPlan({
...plan,
- // ...so that it has the updated parent.
+ // ...pour qu’il ait le parent à jour
[parentId]: nextParent
});
}
@@ -1168,7 +1171,7 @@ export default function TravelPlan() {
const planetIds = root.childIds;
return (
<>
-
Places to visit
+
Lieux à visiter
{planetIds.map(id => (
{
onComplete(parentId, id);
}}>
- Complete
+ C’est fait
{childIds.length > 0 &&
@@ -1222,14 +1225,14 @@ export const initialTravelPlan = {
},
1: {
id: 1,
- title: 'Earth',
+ title: 'Terre',
childIds: [2, 10, 19, 27, 35]
},
2: {
id: 2,
- title: 'Africa',
+ title: 'Afrique',
childIds: [3, 4, 5, 6 , 7, 8, 9]
- },
+ },
3: {
id: 3,
title: 'Botswana',
@@ -1237,7 +1240,7 @@ export const initialTravelPlan = {
},
4: {
id: 4,
- title: 'Egypt',
+ title: 'Egypte',
childIds: []
},
5: {
@@ -1249,42 +1252,42 @@ export const initialTravelPlan = {
id: 6,
title: 'Madagascar',
childIds: []
- },
+ },
7: {
id: 7,
- title: 'Morocco',
+ title: 'Maroc',
childIds: []
},
8: {
id: 8,
- title: 'Nigeria',
+ title: 'Nigéria',
childIds: []
},
9: {
id: 9,
- title: 'South Africa',
+ title: 'Afrique du Sud',
childIds: []
},
10: {
id: 10,
- title: 'Americas',
- childIds: [11, 12, 13, 14, 15, 16, 17, 18],
+ title: 'Amérique',
+ childIds: [11, 12, 13, 14, 15, 16, 17, 18],
},
11: {
id: 11,
- title: 'Argentina',
+ title: 'Argentine',
childIds: []
},
12: {
id: 12,
- title: 'Brazil',
+ title: 'Brésil',
childIds: []
},
13: {
id: 13,
- title: 'Barbados',
+ title: 'Barbade',
childIds: []
- },
+ },
14: {
id: 14,
title: 'Canada',
@@ -1292,17 +1295,17 @@ export const initialTravelPlan = {
},
15: {
id: 15,
- title: 'Jamaica',
+ title: 'Jamaïque',
childIds: []
},
16: {
id: 16,
- title: 'Mexico',
+ title: 'Mexique',
childIds: []
},
17: {
id: 17,
- title: 'Trinidad and Tobago',
+ title: 'Trinité-et-Tobago',
childIds: []
},
18: {
@@ -1312,12 +1315,12 @@ export const initialTravelPlan = {
},
19: {
id: 19,
- title: 'Asia',
- childIds: [20, 21, 22, 23, 24, 25, 26],
+ title: 'Asie',
+ childIds: [20, 21, 22, 23, 24, 25, 26],
},
20: {
id: 20,
- title: 'China',
+ title: 'Chine',
childIds: []
},
21: {
@@ -1327,22 +1330,22 @@ export const initialTravelPlan = {
},
22: {
id: 22,
- title: 'India',
+ title: 'Inde',
childIds: []
},
23: {
id: 23,
- title: 'Singapore',
+ title: 'Singapour',
childIds: []
},
24: {
id: 24,
- title: 'South Korea',
+ title: 'Corée du Sud',
childIds: []
},
25: {
id: 25,
- title: 'Thailand',
+ title: 'Thaïlande',
childIds: []
},
26: {
@@ -1353,11 +1356,11 @@ export const initialTravelPlan = {
27: {
id: 27,
title: 'Europe',
- childIds: [28, 29, 30, 31, 32, 33, 34],
+ childIds: [28, 29, 30, 31, 32, 33, 34],
},
28: {
id: 28,
- title: 'Croatia',
+ title: 'Croatie',
childIds: []
},
29: {
@@ -1367,12 +1370,12 @@ export const initialTravelPlan = {
},
30: {
id: 30,
- title: 'Germany',
+ title: 'Allemagne',
childIds: []
},
31: {
id: 31,
- title: 'Italy',
+ title: 'Italie',
childIds: []
},
32: {
@@ -1382,47 +1385,47 @@ export const initialTravelPlan = {
},
33: {
id: 33,
- title: 'Spain',
+ title: 'Espagne',
childIds: []
},
34: {
id: 34,
- title: 'Turkey',
+ title: 'Turquie',
childIds: []
},
35: {
id: 35,
- title: 'Oceania',
- childIds: [36, 37, 38, 39, 40, 41,, 42],
+ title: 'Océanie',
+ childIds: [36, 37, 38, 39, 40, 41,, 42],
},
36: {
id: 36,
- title: 'Australia',
+ title: 'Australie',
childIds: []
},
37: {
id: 37,
- title: 'Bora Bora (French Polynesia)',
+ title: 'Bora Bora (Polynésie Française)',
childIds: []
},
38: {
id: 38,
- title: 'Easter Island (Chile)',
+ title: 'Ile de Pâques (Chili)',
childIds: []
},
39: {
id: 39,
- title: 'Fiji',
+ title: 'Fidji',
childIds: []
},
40: {
id: 40,
- title: 'Hawaii (the USA)',
+ title: 'Hawaï (USA)',
childIds: []
},
41: {
id: 41,
- title: 'New Zealand',
+ title: 'Nouvelle Zélande',
childIds: []
},
42: {
@@ -1432,7 +1435,7 @@ export const initialTravelPlan = {
},
43: {
id: 43,
- title: 'Moon',
+ title: 'Lune',
childIds: [44, 45, 46]
},
44: {
@@ -1474,13 +1477,13 @@ button { margin: 10px; }
-You can nest state as much as you like, but making it "flat" can solve numerous problems. It makes state easier to update, and it helps ensure you don't have duplication in different parts of a nested object.
+Vous pouvez imbriquer des états autant que vous le souhaitez, mais les rendre « plats » peut résoudre de nombreux problèmes. Ça facilite la mise à jour de l’état, et ça permet de s’assurer qu’il n’y a pas de duplication dans les différentes parties d’un objet imbriqué.
-#### Improving memory usage {/*improving-memory-usage*/}
+#### Consommer moins de mémoire {/*improving-memory-usage*/}
-Ideally, you would also remove the deleted items (and their children!) from the "table" object to improve memory usage. This version does that. It also [uses Immer](/learn/updating-objects-in-state#write-concise-update-logic-with-immer) to make the update logic more concise.
+Idéalement, vous devriez également enlever les éléments supprimés (et leurs enfants !) depuis l’objet « table » pour consommer moins de mémoire. C’est ce que fait cette version. Elle utilise également [Immer](/learn/updating-objects-in-state#write-concise-update-logic-with-immer) pour rendre la logique de mise à jour plus concise.
@@ -1493,12 +1496,12 @@ export default function TravelPlan() {
function handleComplete(parentId, childId) {
updatePlan(draft => {
- // Remove from the parent place's child IDs.
+ // Retirer des ID de lieux enfants du parent.
const parent = draft[parentId];
parent.childIds = parent.childIds
.filter(id => id !== childId);
- // Forget this place and all its subtree.
+ // Oublier cet endroit et tout ce qu'il contient.
deleteAllChildren(childId);
function deleteAllChildren(id) {
const place = draft[id];
@@ -1512,7 +1515,7 @@ export default function TravelPlan() {
const planetIds = root.childIds;
return (
<>
-
Places to visit
+
Lieux à visiter
{planetIds.map(id => (
{
onComplete(parentId, id);
}}>
- Complete
+ C’est fait
{childIds.length > 0 &&
@@ -1566,14 +1569,14 @@ export const initialTravelPlan = {
},
1: {
id: 1,
- title: 'Earth',
+ title: 'Terre',
childIds: [2, 10, 19, 27, 35]
},
2: {
id: 2,
- title: 'Africa',
+ title: 'Afrique',
childIds: [3, 4, 5, 6 , 7, 8, 9]
- },
+ },
3: {
id: 3,
title: 'Botswana',
@@ -1581,7 +1584,7 @@ export const initialTravelPlan = {
},
4: {
id: 4,
- title: 'Egypt',
+ title: 'Egypte',
childIds: []
},
5: {
@@ -1593,42 +1596,42 @@ export const initialTravelPlan = {
id: 6,
title: 'Madagascar',
childIds: []
- },
+ },
7: {
id: 7,
- title: 'Morocco',
+ title: 'Maroc',
childIds: []
},
8: {
id: 8,
- title: 'Nigeria',
+ title: 'Nigéria',
childIds: []
},
9: {
id: 9,
- title: 'South Africa',
+ title: 'Afrique du Sud',
childIds: []
},
10: {
id: 10,
- title: 'Americas',
- childIds: [11, 12, 13, 14, 15, 16, 17, 18],
+ title: 'Amérique',
+ childIds: [11, 12, 13, 14, 15, 16, 17, 18],
},
11: {
id: 11,
- title: 'Argentina',
+ title: 'Argentine',
childIds: []
},
12: {
id: 12,
- title: 'Brazil',
+ title: 'Brésil',
childIds: []
},
13: {
id: 13,
- title: 'Barbados',
+ title: 'Barbade',
childIds: []
- },
+ },
14: {
id: 14,
title: 'Canada',
@@ -1636,17 +1639,17 @@ export const initialTravelPlan = {
},
15: {
id: 15,
- title: 'Jamaica',
+ title: 'Jamaïque',
childIds: []
},
16: {
id: 16,
- title: 'Mexico',
+ title: 'Mexique',
childIds: []
},
17: {
id: 17,
- title: 'Trinidad and Tobago',
+ title: 'Trinité-et-Tobago',
childIds: []
},
18: {
@@ -1656,12 +1659,12 @@ export const initialTravelPlan = {
},
19: {
id: 19,
- title: 'Asia',
- childIds: [20, 21, 22, 23, 24, 25, 26],
+ title: 'Asie',
+ childIds: [20, 21, 22, 23, 24, 25, 26],
},
20: {
id: 20,
- title: 'China',
+ title: 'Chine',
childIds: []
},
21: {
@@ -1671,22 +1674,22 @@ export const initialTravelPlan = {
},
22: {
id: 22,
- title: 'India',
+ title: 'Inde',
childIds: []
},
23: {
id: 23,
- title: 'Singapore',
+ title: 'Singapour',
childIds: []
},
24: {
id: 24,
- title: 'South Korea',
+ title: 'Corée du Sud',
childIds: []
},
25: {
id: 25,
- title: 'Thailand',
+ title: 'Thaïlande',
childIds: []
},
26: {
@@ -1697,11 +1700,11 @@ export const initialTravelPlan = {
27: {
id: 27,
title: 'Europe',
- childIds: [28, 29, 30, 31, 32, 33, 34],
+ childIds: [28, 29, 30, 31, 32, 33, 34],
},
28: {
id: 28,
- title: 'Croatia',
+ title: 'Croatie',
childIds: []
},
29: {
@@ -1711,12 +1714,12 @@ export const initialTravelPlan = {
},
30: {
id: 30,
- title: 'Germany',
+ title: 'Allemagne',
childIds: []
},
31: {
id: 31,
- title: 'Italy',
+ title: 'Italie',
childIds: []
},
32: {
@@ -1726,47 +1729,47 @@ export const initialTravelPlan = {
},
33: {
id: 33,
- title: 'Spain',
+ title: 'Espagne',
childIds: []
},
34: {
id: 34,
- title: 'Turkey',
+ title: 'Turquie',
childIds: []
},
35: {
id: 35,
- title: 'Oceania',
- childIds: [36, 37, 38, 39, 40, 41,, 42],
+ title: 'Océanie',
+ childIds: [36, 37, 38, 39, 40, 41,, 42],
},
36: {
id: 36,
- title: 'Australia',
+ title: 'Australie',
childIds: []
},
37: {
id: 37,
- title: 'Bora Bora (French Polynesia)',
+ title: 'Bora Bora (Polynésie Française)',
childIds: []
},
38: {
id: 38,
- title: 'Easter Island (Chile)',
+ title: 'Ile de Pâques (Chili)',
childIds: []
},
39: {
id: 39,
- title: 'Fiji',
+ title: 'Fidji',
childIds: []
},
40: {
id: 40,
- title: 'Hawaii (the USA)',
+ title: 'Hawaï (USA)',
childIds: []
},
41: {
id: 41,
- title: 'New Zealand',
+ title: 'Nouvelle Zélande',
childIds: []
},
42: {
@@ -1776,7 +1779,7 @@ export const initialTravelPlan = {
},
43: {
id: 43,
- title: 'Moon',
+ title: 'Lune',
childIds: [44, 45, 46]
},
44: {
@@ -1838,25 +1841,25 @@ button { margin: 10px; }
-Sometimes, you can also reduce state nesting by moving some of the nested state into the child components. This works well for ephemeral UI state that doesn't need to be stored, like whether an item is hovered.
+Parfois, vous pouvez aussi réduire l’imbrication des états en déplaçant une partie de l’état imbriqué dans les composants enfants. C'est bien adapté aux états éphémères de l’UI qui n’ont pas besoin d’être stockés, comme le fait de savoir si un élément est survolé.
-* If two state variables always update together, consider merging them into one.
-* Choose your state variables carefully to avoid creating "impossible" states.
-* Structure your state in a way that reduces the chances that you'll make a mistake updating it.
-* Avoid redundant and duplicate state so that you don't need to keep it in sync.
-* Don't put props *into* state unless you specifically want to prevent updates.
-* For UI patterns like selection, keep ID or index in state instead of the object itself.
-* If updating deeply nested state is complicated, try flattening it.
+* Si deux variables d’état sont toujours mises à jour ensemble, envisagez de les fusionner en une seule.
+* Choisissez soigneusement vos variables d’état pour éviter de créer des états « impossibles ».
+* Structurez votre état de manière à réduire les risques d’erreur lors de sa mise à jour.
+* Evitez les états dupliqués et redondants afin de ne pas avoir à les synchroniser.
+* Ne mettez pas de props *dans* un état à moins que vous ne vouliez spécifiquement empêcher les mises à jour.
+* Pour les interactions telles que la sélection d'élément, conservez l’ID ou l’index dans l’état au lieu de référencer l’objet lui-même.
+* Si la mise à jour d’un état profondément imbriqué est compliquée, essayez de l’aplatir.
-#### Fix a component that's not updating {/*fix-a-component-thats-not-updating*/}
+#### Réparer un composant qui ne s’actualise pas {/*fix-a-component-thats-not-updating*/}
-This `Clock` component receives two props: `color` and `time`. When you select a different color in the select box, the `Clock` component receives a different `color` prop from its parent component. However, for some reason, the displayed color doesn't update. Why? Fix the problem.
+Ce composant `Clock` reçoit deux props : `color` et `time`. Lorsque vous sélectionnez une couleur différente dans la boîte de sélection, le composant `Clock` reçoit une prop `color` différente depuis son composant parent. Cependant, la couleur affichée n’est pas mise à jour. Pourquoi ? Corrigez le problème.
@@ -1894,7 +1897,7 @@ export default function App() {
return (
- Pick a color:{' '}
+ Choisissez une couleur :{' '}