From 280cc396d3b96c840277797eec19a41ad56710c4 Mon Sep 17 00:00:00 2001 From: Christophe Porteneuve Date: Wed, 5 Jul 2023 18:11:03 +0200 Subject: [PATCH 1/3] copy(thinking-in-react): first full translation --- src/content/learn/thinking-in-react.md | 321 +++++++++++++------------ 1 file changed, 161 insertions(+), 160 deletions(-) diff --git a/src/content/learn/thinking-in-react.md b/src/content/learn/thinking-in-react.md index 23d4beb3f..d9c1145a6 100644 --- a/src/content/learn/thinking-in-react.md +++ b/src/content/learn/thinking-in-react.md @@ -1,49 +1,49 @@ --- -title: Thinking in React +title: Penser en React --- -React can change how you think about the designs you look at and the apps you build. When you build a user interface with React, you will first break it apart into pieces called *components*. Then, you will describe the different visual states for each of your components. Finally, you will connect your components together so that the data flows through them. In this tutorial, we’ll guide you through the thought process of building a searchable product data table with React. +React peut changer votre façon de penser aux designs que vous observez et aux applis que vous construisez. Lorsque vous construirez une interface utilisateur (UI) avec React, vous commencerez par la décomposer en éléments appelés *composants*. Ensuite, vous décrirez les différents états visuels de chaque composant. Enfin, vous brancherez vos composants ensemble de façon à ce que les données circulent entre eux. Dans ce tutoriel, nous allons vous guider à travers le processus mental de construction d'un tableau de données produit filtrable en utilisant React. -## Start with the mockup {/*start-with-the-mockup*/} +## Partir de la maquette {/*start-with-the-mockup*/} -Imagine that you already have a JSON API and a mockup from a designer. +Imaginons que vous ayez déjà une API JSON et une maquette fournie par la designer. -The JSON API returns some data that looks like this: +L'API JSON renvoie des données qui ressemblent à ça : ```json [ - { category: "Fruits", price: "$1", stocked: true, name: "Apple" }, - { category: "Fruits", price: "$1", stocked: true, name: "Dragonfruit" }, - { category: "Fruits", price: "$2", stocked: false, name: "Passionfruit" }, - { category: "Vegetables", price: "$2", stocked: true, name: "Spinach" }, - { category: "Vegetables", price: "$4", stocked: false, name: "Pumpkin" }, - { category: "Vegetables", price: "$1", stocked: true, name: "Peas" } + { category: "Fruits", price: "$1", stocked: true, name: "Pomme" }, + { category: "Fruits", price: "$1", stocked: true, name: "Fruit du dragon" }, + { category: "Fruits", price: "$2", stocked: false, name: "Fruit de la passion" }, + { category: "Légumes", price: "$2", stocked: true, name: "Épinard" }, + { category: "Légumes", price: "$4", stocked: false, name: "Citrouille" }, + { category: "Légumes", price: "$1", stocked: true, name: "Petits pois" } ] ``` -The mockup looks like this: +La maquette ressemble à ça : -To implement a UI in React, you will usually follow the same five steps. +Pour implémenter cette UI en React, vous allez généralement devoir suivre les mêmes cinq étapes. -## Step 1: Break the UI into a component hierarchy {/*step-1-break-the-ui-into-a-component-hierarchy*/} +## Étape 1 : décomposer l'UI en une hiérarchie de composants {/*step-1-break-the-ui-into-a-component-hierarchy*/} -Start by drawing boxes around every component and subcomponent in the mockup and naming them. If you work with a designer, they may have already named these components in their design tool. Ask them! +Commencez par dessiner des boîtes autour de chaque composant et sous-composant sur la maquette, et nommez-les. Si vous travaillez avec un·e designer, iel aura peut-être déjà nommé ces composants dans ses outils de design : demandez-lui ! -Depending on your background, you can think about splitting up a design into components in different ways: +En fonction de votre propre vécu, vous pouvez imaginer la découpe du design en composant selon divers axes : -* **Programming**--use the same techniques for deciding if you should create a new function or object. One such technique is the [single responsibility principle](https://en.wikipedia.org/wiki/Single_responsibility_principle), that is, a component should ideally only do one thing. If it ends up growing, it should be decomposed into smaller subcomponents. -* **CSS**--consider what you would make class selectors for. (However, components are a bit less granular.) -* **Design**--consider how you would organize the design's layers. +- **Programmatique** : utilisez les mêmes techniques d'arbitrage que si vous deviez créer une nouvelle fonction ou un nouvel objet. Une de ces techniques réside dans le [principe de responsabilité unique](https://fr.wikipedia.org/wiki/Principe_de_responsabilit%C3%A9_unique), qui veut qu'un composant ne doive idéalement faire qu'une seule chose. S'il se retrouve à grandir, il devrait sans doute être décomposé en sous-composants plus simples. +- **CSS** : réfléchissez aux endroits pour lesquels vous définiriez un sélecteur de classe. (Ceci dit, les composants sont un peu moins granulaires.) +- **Design** : imaginez comment vous organiseriez les couches du design. -If your JSON is well-structured, you'll often find that it naturally maps to the component structure of your UI. That's because UI and data models often have the same information architecture--that is, the same shape. Separate your UI into components, where each component matches one piece of your data model. +Si votre JSON est bien structuré, vous constaterez souvent qu'il a une sorte de correspondance naturelle à la structure des composants de votre UI. C'est parce que l'UI et les modèles de données ont souvent la même architecture d'information — la même forme, en somme. Découpez votre UI en composants, avec chaque composant qui correspond à une partie de votre modèle de données. -There are five components on this screen: +Il y a cinq composants sur cet écran : @@ -51,33 +51,33 @@ There are five components on this screen: -1. `FilterableProductTable` (grey) contains the entire app. -2. `SearchBar` (blue) receives the user input. -3. `ProductTable` (lavender) displays and filters the list according to the user input. -4. `ProductCategoryRow` (green) displays a heading for each category. -5. `ProductRow` (yellow) displays a row for each product. +1. `FilterableProductTable` (gris) contient l'appli entière. +2. `SearchBar` (bleu) reçoit les saisies de l'utilisateur. +3. `ProductTable` (mauve) affiche et filtre la liste en fonction de la saisie utilisateur. +4. `ProductCategoryRow` (vert) affiche un en-tête pour chaque catégorie. +5. `ProductRow` (jaune) affiche une ligne pour chaque produit. -If you look at `ProductTable` (lavender), you'll see that the table header (containing the "Name" and "Price" labels) isn't its own component. This is a matter of preference, and you could go either way. For this example, it is a part of `ProductTable` because it appears inside the `ProductTable`'s list. However, if this header grows to be complex (e.g., if you add sorting), you can move it into its own `ProductTableHeader` component. +Si vous examinez `ProductTable` (en mauve), vous verrez que l'en-tête du tableau (qui contient les libellés « Nom » et « Prix ») n'a pas son propre composant. C'est une question de préférence personnelle, et les deux approches se valent. Dans cet exemple, il fait partie de `ProductTable` parce qu'il apparaît au sein de la liste de `ProductTable`. Ceci dit, si cet en-tête devenait complexe (par exemple en ajoutant des déclencheurs de tri), vous pourriez l'extraire vers son propre composant `ProductTableHeader`. -Now that you've identified the components in the mockup, arrange them into a hierarchy. Components that appear within another component in the mockup should appear as a child in the hierarchy: +Maintenant que vous avez identifié les composants de la maquette, déterminez leur hiérarchie. Les composants qui apparaissent au sein d'un autre composant dans la maquette devraient apparaître comme enfants dans cette arborescence : -* `FilterableProductTable` - * `SearchBar` - * `ProductTable` - * `ProductCategoryRow` - * `ProductRow` +- `FilterableProductTable` + - `SearchBar` + - `ProductTable` + - `ProductCategoryRow` + - `ProductRow` -## Step 2: Build a static version in React {/*step-2-build-a-static-version-in-react*/} +## Étape 2 : construire une version statique en React {/*step-2-build-a-static-version-in-react*/} -Now that you have your component hierarchy, it's time to implement your app. The most straightforward approach is to build a version that renders the UI from your data model without adding any interactivity... yet! It's often easier to build the static version first and add interactivity later. Building a static version requires a lot of typing and no thinking, but adding interactivity requires a lot of thinking and not a lot of typing. +À présent que vous avez votre hiérarchie de composants, il est temps d'implémenter votre appli. L'approche la plus directe consiste à construire une version qui affiche l'UI à partir du modèle de données, sans en gérer l'interactivité… pour le moment ! Il est souvent plus facile de construire une version statique d'abord et d'ajouter l'interactivité ensuite. Construire une version statique nécessite beaucoup de saisie mais peu de réflexion, alors qu'ajouter de l'interactivité nécessite beaucoup de réflexion mais peu de saisie. -To build a static version of your app that renders your data model, you'll want to build [components](/learn/your-first-component) that reuse other components and pass data using [props.](/learn/passing-props-to-a-component) Props are a way of passing data from parent to child. (If you're familiar with the concept of [state](/learn/state-a-components-memory), don't use state at all to build this static version. State is reserved only for interactivity, that is, data that changes over time. Since this is a static version of the app, you don't need it.) +Pour construire une version statique de votre appli qui affiche votre modèle de données, vous aurez besoin de construire des [composants](/learn/your-first-component) qui en réutilisent d'autres et leur passent des données grâce aux [props](/learn/passing-props-to-a-component). Les props sont un moyen de passer des données du parent aux enfants. (Si vous êtes à l'aise avec la notion d'[état](/learn/state-a-components-memory), n'utilisez pas d'état pour construire cette version statique. L'état est réservé à l'interactivité, c'est-à-dire à des données qui changent avec le temps. Puisque vous construisez une version statique de l'appli, vous n'en avez pas besoin.) -You can either build "top down" by starting with building the components higher up in the hierarchy (like `FilterableProductTable`) or "bottom up" by working from components lower down (like `ProductRow`). In simpler examples, it’s usually easier to go top-down, and on larger projects, it’s easier to go bottom-up. +Vous pouvez construire l'appli soit « de haut en bas », en commençant par construire les composants les plus en haut de la hiérarchie (tels que `FilterableProductTable`), soit « de bas en haut », en commençant par les composants de niveau inférieur (tels que `ProductRow`). Dans des contextes simples, il est généralement plus facile de procéder de haut en bas, et sur les projets plus complexes, il est plus aisé de procéder de bas en haut. @@ -130,8 +130,8 @@ function ProductTable({ products }) { - - + + {rows} @@ -142,11 +142,11 @@ function ProductTable({ products }) { function SearchBar() { return ( - + ); @@ -162,12 +162,12 @@ function FilterableProductTable({ products }) { } const PRODUCTS = [ - {category: "Fruits", price: "$1", stocked: true, name: "Apple"}, - {category: "Fruits", price: "$1", stocked: true, name: "Dragonfruit"}, - {category: "Fruits", price: "$2", stocked: false, name: "Passionfruit"}, - {category: "Vegetables", price: "$2", stocked: true, name: "Spinach"}, - {category: "Vegetables", price: "$4", stocked: false, name: "Pumpkin"}, - {category: "Vegetables", price: "$1", stocked: true, name: "Peas"} + { category: "Fruits", price: "1 €", stocked: true, name: "Pomme" }, + { category: "Fruits", price: "1 €", stocked: true, name: "Fruit du dragon" }, + { category: "Fruits", price: "2 €", stocked: false, name: "Fruit de la passion" }, + { category: "Légumes", price: "2 €", stocked: true, name: "Épinard" }, + { category: "Légumes", price: "4 €", stocked: false, name: "Citrouille" }, + { category: "Légumes", price: "1 €", stocked: true, name: "Petits pois" } ]; export default function App() { @@ -195,107 +195,107 @@ td { -(If this code looks intimidating, go through the [Quick Start](/learn/) first!) +(Si ce code vous paraît intimidant, faites un détour par notre [démarrage rapide](/learn/) d'abord !) -After building your components, you'll have a library of reusable components that render your data model. Because this is a static app, the components will only return JSX. The component at the top of the hierarchy (`FilterableProductTable`) will take your data model as a prop. This is called _one-way data flow_ because the data flows down from the top-level component to the ones at the bottom of the tree. +Après avoir construit vos composants, vous disposerez d'une bibliothèque de composants réutilisables qui afficheront votre modèle de données. Puisque vous construisez ici une version statique de l'appli, ces composants ne renvoient que du JSX. Le composant au sommet de la hiérarchie (`FilterableProductTable`) prendra votre modèle de données comme prop. On parle de *flux de données unidirectionnel* parce que les données circulent uniquement en descente, du composant racine vers ceux tout en bas de l'arborescence. -At this point, you should not be using any state values. That’s for the next step! +À ce stade, vous ne devriez utiliser aucune valeur d'état. Ce sera pour la prochaine étape ! -## Step 3: Find the minimal but complete representation of UI state {/*step-3-find-the-minimal-but-complete-representation-of-ui-state*/} +## Étape 3 : trouver une représentation minimale suffisante de l'état de l'UI {/*step-3-find-the-minimal-but-complete-representation-of-ui-state*/} -To make the UI interactive, you need to let users change your underlying data model. You will use *state* for this. +Pour rendre votre UI interactive, vous allez devoir permettre aux utilisateurs de modifier le modèle de données sous-jacent. Vous utiliserez *l'état* pour ça. -Think of state as the minimal set of changing data that your app needs to remember. The most important principle for structuring state is to keep it [DRY (Don't Repeat Yourself).](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) Figure out the absolute minimal representation of the state your application needs and compute everything else on-demand. For example, if you're building a shopping list, you can store the items as an array in state. If you want to also display the number of items in the list, don't store the number of items as another state value--instead, read the length of your array. +Considérez l'état comme le jeu minimum de données susceptibles de changer dont votre appli doit se souvenir. Le principe le plus important pour structurer l'état consiste à le maintenir [DRY *(Don't Repeat Yourself)*](https://fr.wikipedia.org/wiki/Ne_vous_r%C3%A9p%C3%A9tez_pas) *(Ne vous répétez pas, NdT)*. Déterminez la plus petite représentation possible de l'état dont votre application a besoin, et calculez tout le reste à la volée. Par exemple, si vous construisez une liste d'achats, vous pouvez en stocker les éléments comme un tableau dans l'état. Si vous avez aussi besoin d'afficher le nombre d'éléments du panier, ne stockez pas ce nombre dans une autre valeur d'état : lisez plutôt la longueur du tableau. -Now think of all of the pieces of data in this example application: +Réfléchissez maintenant à toutes les données dans cette application d'exemple : -1. The original list of products -2. The search text the user has entered -3. The value of the checkbox -4. The filtered list of products +1. La liste originale des produits +2. Le texte de recherche saisi par l'utilisateur +3. L'état de la case à cocher +4. La liste filtrée des produits -Which of these are state? Identify the ones that are not: +Qu'est-ce qui constitue de l'état là-dedans ? Identifiez ce qui n'en est pas : -* Does it **remain unchanged** over time? If so, it isn't state. -* Is it **passed in from a parent** via props? If so, it isn't state. -* **Can you compute it** based on existing state or props in your component? If so, it *definitely* isn't state! +- Est-ce que ça **reste inchangé** au fil du temps ? Si oui, ce n'est pas de l'état. +- Est-ce que c'est **passé depuis un parent** *via* les props ? Si oui, ce n'est pas de l'état. +- **Pouvez-vous le calculer** sur base d'états ou props existants de votre composant ? Si oui, ce n'est *clairement* pas de l'état ! -What's left is probably state. +Ce qui reste est sans doute de l'état. -Let's go through them one by one again: +Refaisons ça pour chaque donnée : -1. The original list of products is **passed in as props, so it's not state.** -2. The search text seems to be state since it changes over time and can't be computed from anything. -3. The value of the checkbox seems to be state since it changes over time and can't be computed from anything. -4. The filtered list of products **isn't state because it can be computed** by taking the original list of products and filtering it according to the search text and value of the checkbox. +1. La liste originale des produits nous est **passée dans les props, donc ce n'est pas de l'état**. +2. Le texte de la recherche semble être de l'état car il change au fil du temps et ne peut être calculé sur aucune autre base. +3. L'état de la case à cocher semble être de l'état car il change au fil du temps et ne peut etre calculé sur aucune autre base. +4. La liste filtrée des produits **n'est pas de l'état car elle peut être calculée** en prenant la liste originale des produits pour la filtrer selon le texte de la rechercher et l'état de la case à cocher. -This means only the search text and the value of the checkbox are state! Nicely done! +Au bout du compte, seuls le texte de la recherche et l'état de la case à cocher sont de l'état ! Bien joué ! -#### Props vs State {/*props-vs-state*/} +#### Props vs. état {/*props-vs-state*/} -There are two types of "model" data in React: props and state. The two are very different: +React propose deux types de données de « modèle » : les props et l'état. Les deux diffèrent drastiquement : -* [**Props** are like arguments you pass](/learn/passing-props-to-a-component) to a function. They let a parent component pass data to a child component and customize its appearance. For example, a `Form` can pass a `color` prop to a `Button`. -* [**State** is like a component’s memory.](/learn/state-a-components-memory) It lets a component keep track of some information and change it in response to interactions. For example, a `Button` might keep track of `isHovered` state. +- [Les **props** sont comme des arguments que vous passez](/learn/passing-props-to-a-component) à une fonction. Elles permettent au composant parent de passer des données à un composant enfant et de personnaliser ainsi son apparence. Par exemple, un `Form` pourrait passer une prop `color` à un `Button`. +- [L'**état** est comme la mémoire du composant](/learn/state-a-components-memory). Il permet au composant de garder trace de certaines informations et de les modifier en réaction à des interactions. Par exemple, un `Button` pourrait vouloir garder trace de son état `isHovered`. -Props and state are different, but they work together. A parent component will often keep some information in state (so that it can change it), and *pass it down* to child components as their props. It's okay if the difference still feels fuzzy on the first read. It takes a bit of practice for it to really stick! +Les props et l'état sont très différents, mais ils collaborent. Un composant parent conservera souvent des informations dans son état (pour pouvoir les faire évoluer) qu'il va **passer** à ses composants enfants *via* leurs props. Si la différence vous semble encore un peu floue après cette première lecture, ne vous en faites pas. Bien la saisir nécessite un peu de pratique ! -## Step 4: Identify where your state should live {/*step-4-identify-where-your-state-should-live*/} +## Étape 4 : identifier où l'état devrait vivre {/*step-4-identify-where-your-state-should-live*/} -After identifying your app’s minimal state data, you need to identify which component is responsible for changing this state, or *owns* the state. Remember: React uses one-way data flow, passing data down the component hierarchy from parent to child component. It may not be immediately clear which component should own what state. This can be challenging if you’re new to this concept, but you can figure it out by following these steps! +Après avoir identifié les données d'état minimales de votre appli, vous allez devoir identifier quel composant est responsable de faire évoluer cet état, c'est-à-dire quel composant *possède* l'état. Souvenez-vous : React utilise un flux de données unidirectionnel, où les données descendent le long de la hiérarchie des composants, des parents vers les enfants. Il n'est pas toujours immédiatement évident de savoir quel composant devrait posséder quel état. C'est difficile si ce concept est nouveau pour vous, mais vous pouvez trouver la réponse en utilisant les étapes qui suivent ! -For each piece of state in your application: +Pour chaque élément d'état de votre application : -1. Identify *every* component that renders something based on that state. -2. Find their closest common parent component--a component above them all in the hierarchy. -3. Decide where the state should live: - 1. Often, you can put the state directly into their common parent. - 2. You can also put the state into some component above their common parent. - 3. If you can't find a component where it makes sense to own the state, create a new component solely for holding the state and add it somewhere in the hierarchy above the common parent component. +1. Identifiez *chaque* composant qui affiche quelque chose sur base de cet état. +2. Trouvez leur plus proche ancêtre commun : un composant qui est au-dessus d'eux tous dans l'aborescence. +3. Décidez où l'état devrait vivre : + 1. Le plus souvent, vous pourrez mettre l'état directement dans leur ancêtre commun. + 2. Vous pouvez aussi le mettre dans un composant au-dessus de leur ancêtre commun. + 3. Si vous ne trouverez aucun composant dans lequel il semble logique de placer l'état, créez un nouveau composant spécifiquement pour contenir l'état, et insérez-le dans l'arborescence juste au-dessus de leur ancêtre commun. -In the previous step, you found two pieces of state in this application: the search input text, and the value of the checkbox. In this example, they always appear together, so it makes sense to put them into the same place. +Lors de l'étape précédente, ous avez trouvé deux éléments d'état pour cette application : le texte de la recherche et l'état de la case à cocher. Dans notre exemple, ils apparaissent toujours ensemble, de sorte qu'il semble lorsque de les placer au même endroit. -Now let's run through our strategy for them: +Déroulons notre stratégie pour eux : -1. **Identify components that use state:** - * `ProductTable` needs to filter the product list based on that state (search text and checkbox value). - * `SearchBar` needs to display that state (search text and checkbox value). -1. **Find their common parent:** The first parent component both components share is `FilterableProductTable`. -2. **Decide where the state lives**: We'll keep the filter text and checked state values in `FilterableProductTable`. +1. **Identifier les composants qui utilisent l'état** : + - `ProductTable` a besoin de filtrer la liste des produits sur base de cet état (texte de la recherche et état de la case à cocher). + - `SearchBar` a besoin d'afficher cet état (texte de la recherche et état de la case à cocher). +2. **Trouver leur ancêtre commun** : le plus proche ancêtre commun à ces deux composants est `FilterableProductTable`. +3. **Décider où l'état devrait vivre** : nous stockerons le texte de la recherche et l'état de la case à cocher dans `FilterableProductTable`. -So the state values will live in `FilterableProductTable`. +Ainsi, les valeurs d'état vivront dans `FilterableProductTable`. -Add state to the component with the [`useState()` Hook.](/reference/react/useState) Hooks are special functions that let you "hook into" React. Add two state variables at the top of `FilterableProductTable` and specify their initial state: +Ajoutez l'état au composant à l'aide du [Hook `useState()`](/reference/react/useState). Les Hooks sont des fonctions spéciales qui vous permettent de « vous accrocher » à React. Ajoutez deux variables d'état à la racine de `FilterableProductTable` et donnez-leur des valeurs initiales : ```js function FilterableProductTable({ products }) { const [filterText, setFilterText] = useState(''); - const [inStockOnly, setInStockOnly] = useState(false); + const [inStockOnly, setInStockOnly] = useState(false); ``` -Then, pass `filterText` and `inStockOnly` to `ProductTable` and `SearchBar` as props: +Ensuite, passez `filterText` et `inStockOnly` à `ProductTable` et `SearchBar` *via* des props : ```js
- -
``` -You can start seeing how your application will behave. Edit the `filterText` initial value from `useState('')` to `useState('fruit')` in the sandbox code below. You'll see both the search input text and the table update: +Vous pouvez commencer à percevoir la façon dont votre application va se comporter. Changez la valeur initiale de `filterText` en passant de `useState('')` à `useState('fruit')` dans le bac à sable ci-dessous. Vous verrez aussi bien le texte de la recherche que le tableau se mettre à jour : @@ -308,10 +308,10 @@ function FilterableProductTable({ products }) { return (
- - @@ -377,8 +377,8 @@ function ProductTable({ products, filterText, inStockOnly }) {
NamePriceNomPrix
- - + + {rows} @@ -389,28 +389,28 @@ function ProductTable({ products, filterText, inStockOnly }) { function SearchBar({ filterText, inStockOnly }) { return ( - + ); } const PRODUCTS = [ - {category: "Fruits", price: "$1", stocked: true, name: "Apple"}, - {category: "Fruits", price: "$1", stocked: true, name: "Dragonfruit"}, - {category: "Fruits", price: "$2", stocked: false, name: "Passionfruit"}, - {category: "Vegetables", price: "$2", stocked: true, name: "Spinach"}, - {category: "Vegetables", price: "$4", stocked: false, name: "Pumpkin"}, - {category: "Vegetables", price: "$1", stocked: true, name: "Peas"} + { category: "Fruits", price: "1 €", stocked: true, name: "Pomme" }, + { category: "Fruits", price: "1 €", stocked: true, name: "Fruit du dragon" }, + { category: "Fruits", price: "2 €", stocked: false, name: "Fruit de la passion" }, + { category: "Légumes", price: "2 €", stocked: true, name: "Épinard" }, + { category: "Légumes", price: "4 €", stocked: false, name: "Citrouille" }, + { category: "Légumes", price: "1 €", stocked: true, name: "Petits pois" } ]; export default function App() { @@ -437,7 +437,7 @@ td { -Notice that editing the form doesn't work yet. There is a console error in the sandbox above explaining why: +Remarquez que la saisie dans le formulaire ne marche pas encore. On voit une erreur dans la console du bac à sable qui nous explique pourquoi : @@ -445,28 +445,29 @@ You provided a \`value\` prop to a form field without an \`onChange\` handler. T -In the sandbox above, `ProductTable` and `SearchBar` read the `filterText` and `inStockOnly` props to render the table, the input, and the checkbox. For example, here is how `SearchBar` populates the input value: +*(« Vous avez fourni une prop `value` au champ de formulaire sans gestionnaire `onChange`. Le champ sera placé en lecture seule. », NdT)* + +Dans le bac à sable ci-dessus, `ProductTable` et `SearchBar` lisent les props `filterText` et `inStockOnly` pour afficher le tableau, le champ de saisie, et la case à cocher. Par exemple, voici comment `SearchBar` fournit la valeur du champ : ```js {1,6} function SearchBar({ filterText, inStockOnly }) { return ( - + ``` -However, you haven't added any code to respond to the user actions like typing yet. This will be your final step. - +Cependant, vous n'avez pas encore ajouté de code pour réagir aux actions de l'utilisateur, comme la saisie. Ce sera notre dernière étape. -## Step 5: Add inverse data flow {/*step-5-add-inverse-data-flow*/} +## Étape 5 : ajouter un flux de données inverse {/*step-5-add-inverse-data-flow*/} -Currently your app renders correctly with props and state flowing down the hierarchy. But to change the state according to user input, you will need to support data flowing the other way: the form components deep in the hierarchy need to update the state in `FilterableProductTable`. +Pour le moment, votre appli s'affiche correctement avec les props et l'état qui circulent le long de son arborescence. Mais pour modifier l'état suite à des saisies utilisateur, vous allez devoir permettre un flux de données dans l'autre sens : les composants de formulaire enfouis dans l'arbre vont avoir besoin de mettre à jour l'état de `FilterableProductTable`. -React makes this data flow explicit, but it requires a little more typing than two-way data binding. If you try to type or check the box in the example above, you'll see that React ignores your input. This is intentional. By writing ``, you've set the `value` prop of the `input` to always be equal to the `filterText` state passed in from `FilterableProductTable`. Since `filterText` state is never set, the input never changes. +React impose que ce flux de données soit explicite, ce qui nécessite un peu plus de frappe que les liaisons de données bidirectionnelles. Si vous essayez de saisir quelque chose dans la recherche, ou de cocher la case dans l'exemple ci-dessus, vous verrez que React ignore vos saisies. C'est voulu. En écrivant ``, vous avez calé la prop `value` de l'`input` pour qu'elle reflète toujours l'état `filterText` passé depuis `FilterableProductTable`. Puisque l'état `filterText` n'est jamais modifié, le champ ne change jamais de valeur. -You want to make it so whenever the user changes the form inputs, the state updates to reflect those changes. The state is owned by `FilterableProductTable`, so only it can call `setFilterText` and `setInStockOnly`. To let `SearchBar` update the `FilterableProductTable`'s state, you need to pass these functions down to `SearchBar`: +Vous souhaitez que chaque fois que l'utilisateur modifie les champs du formulaire, l'état soit mis à jour pour refléter ces changements. L'état appartient à `FilterableProductTable`, de sorte que seul ce composant peut appeler `setFilterText` et `setInStockOnly`. Pour permettre à `SearchBar` de mettre à jour l'état de `FilterableProductTable`, vous allez devoir lui passer des fonctions `SearchBar` : ```js {2,3,10,11} function FilterableProductTable({ products }) { @@ -475,24 +476,24 @@ function FilterableProductTable({ products }) { return (
- ``` -Inside the `SearchBar`, you will add the `onChange` event handlers and set the parent state from them: +Au sein de `Searchbar`, ajoutez des gestionnaires d'événements `onChange` et utilisez-les pour modifier l'état du parent : ```js {5} - onFilterTextChange(e.target.value)} /> ``` -Now the application fully works! +À présent votre application fonctionne complètement ! @@ -505,13 +506,13 @@ function FilterableProductTable({ products }) { return (
- -
@@ -576,8 +577,8 @@ function ProductTable({ products, filterText, inStockOnly }) {
NamePriceNomPrix
- - + + {rows} @@ -593,29 +594,29 @@ function SearchBar({ }) { return ( - onFilterTextChange(e.target.value)} /> ); } const PRODUCTS = [ - {category: "Fruits", price: "$1", stocked: true, name: "Apple"}, - {category: "Fruits", price: "$1", stocked: true, name: "Dragonfruit"}, - {category: "Fruits", price: "$2", stocked: false, name: "Passionfruit"}, - {category: "Vegetables", price: "$2", stocked: true, name: "Spinach"}, - {category: "Vegetables", price: "$4", stocked: false, name: "Pumpkin"}, - {category: "Vegetables", price: "$1", stocked: true, name: "Peas"} + { category: "Fruits", price: "1 €", stocked: true, name: "Pomme" }, + { category: "Fruits", price: "1 €", stocked: true, name: "Fruit du dragon" }, + { category: "Fruits", price: "2 €", stocked: false, name: "Fruit de la passion" }, + { category: "Légumes", price: "2 €", stocked: true, name: "Épinard" }, + { category: "Légumes", price: "4 €", stocked: false, name: "Citrouille" }, + { category: "Légumes", price: "1 €", stocked: true, name: "Petits pois" } ]; export default function App() { @@ -642,8 +643,8 @@ td { -You can learn all about handling events and updating state in the [Adding Interactivity](/learn/adding-interactivity) section. +Vous pourrez apprendre tout ce qu'il y a à savoir sur la gestion des événements et la mise à jour de l'état dans la section [Ajouter de l'interactivité](/learn/adding-interactivity). -## Where to go from here {/*where-to-go-from-here*/} +## Et maintenant ? {/*where-to-go-from-here*/} -This was a very brief introduction to how to think about building components and applications with React. You can [start a React project](/learn/installation) right now or [dive deeper on all the syntax](/learn/describing-the-ui) used in this tutorial. +C'était une introduction très rapide sur la façon de penser lorsqu'on construit des composants et applications avec React. Vous pouvez [démarrer un projet React](/learn/installation) dès maintenant ou [explorer plus en détails](/learn/describing-the-ui) toutes les syntaxes utilisées dans ce tutoriel. From d24757c1b6a85545e392ce437873289aa0cb1e0d Mon Sep 17 00:00:00 2001 From: Christophe Porteneuve Date: Wed, 5 Jul 2023 18:26:44 +0200 Subject: [PATCH 2/3] copy(thinking-in-react): final review pass" --- src/content/learn/thinking-in-react.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/content/learn/thinking-in-react.md b/src/content/learn/thinking-in-react.md index d9c1145a6..e85ef5144 100644 --- a/src/content/learn/thinking-in-react.md +++ b/src/content/learn/thinking-in-react.md @@ -4,7 +4,7 @@ title: Penser en React -React peut changer votre façon de penser aux designs que vous observez et aux applis que vous construisez. Lorsque vous construirez une interface utilisateur (UI) avec React, vous commencerez par la décomposer en éléments appelés *composants*. Ensuite, vous décrirez les différents états visuels de chaque composant. Enfin, vous brancherez vos composants ensemble de façon à ce que les données circulent entre eux. Dans ce tutoriel, nous allons vous guider à travers le processus mental de construction d'un tableau de données produit filtrable en utilisant React. +React peut changer votre façon de penser aux designs que vous observez et aux applis que vous construisez. Lorsque vous construirez une interface utilisateur (UI) avec React, vous commencerez par la décomposer en éléments appelés *composants*. Ensuite, vous décrirez les différents états visuels de chaque composant. Enfin, vous brancherez vos composants ensemble de façon à ce que les données circulent entre eux. Dans ce tutoriel, nous allons vous guider à travers le processus mental de construction d'un tableau de données de produits filtrable, en utilisant React. @@ -35,7 +35,7 @@ Pour implémenter cette UI en React, vous allez généralement devoir suivre les Commencez par dessiner des boîtes autour de chaque composant et sous-composant sur la maquette, et nommez-les. Si vous travaillez avec un·e designer, iel aura peut-être déjà nommé ces composants dans ses outils de design : demandez-lui ! -En fonction de votre propre vécu, vous pouvez imaginer la découpe du design en composant selon divers axes : +En fonction de votre propre vécu, vous pouvez aborder la découpe du design en composants selon divers axes : - **Programmatique** : utilisez les mêmes techniques d'arbitrage que si vous deviez créer une nouvelle fonction ou un nouvel objet. Une de ces techniques réside dans le [principe de responsabilité unique](https://fr.wikipedia.org/wiki/Principe_de_responsabilit%C3%A9_unique), qui veut qu'un composant ne doive idéalement faire qu'une seule chose. S'il se retrouve à grandir, il devrait sans doute être décomposé en sous-composants plus simples. - **CSS** : réfléchissez aux endroits pour lesquels vous définiriez un sélecteur de classe. (Ceci dit, les composants sont un peu moins granulaires.) @@ -75,7 +75,7 @@ Maintenant que vous avez identifié les composants de la maquette, déterminez l À présent que vous avez votre hiérarchie de composants, il est temps d'implémenter votre appli. L'approche la plus directe consiste à construire une version qui affiche l'UI à partir du modèle de données, sans en gérer l'interactivité… pour le moment ! Il est souvent plus facile de construire une version statique d'abord et d'ajouter l'interactivité ensuite. Construire une version statique nécessite beaucoup de saisie mais peu de réflexion, alors qu'ajouter de l'interactivité nécessite beaucoup de réflexion mais peu de saisie. -Pour construire une version statique de votre appli qui affiche votre modèle de données, vous aurez besoin de construire des [composants](/learn/your-first-component) qui en réutilisent d'autres et leur passent des données grâce aux [props](/learn/passing-props-to-a-component). Les props sont un moyen de passer des données du parent aux enfants. (Si vous êtes à l'aise avec la notion d'[état](/learn/state-a-components-memory), n'utilisez pas d'état pour construire cette version statique. L'état est réservé à l'interactivité, c'est-à-dire à des données qui changent avec le temps. Puisque vous construisez une version statique de l'appli, vous n'en avez pas besoin.) +Pour construire une version statique de votre appli qui affiche votre modèle de données, vous aurez besoin de construire des [composants](/learn/your-first-component) qui en réutilisent d'autres et leur passent des données grâce aux [props](/learn/passing-props-to-a-component). Les props sont un moyen de passer des données du parent aux enfants. (Si vous êtes à l'aise avec la notion d'[état](/learn/state-a-components-memory), n'utilisez pas d'état pour construire cette version statique. L'état est réservé à l'interactivité, c'est-à-dire à des données qui changent avec le temps. Vous construisez une version statique : vous n'en avez pas besoin.) Vous pouvez construire l'appli soit « de haut en bas », en commençant par construire les composants les plus en haut de la hiérarchie (tels que `FilterableProductTable`), soit « de bas en haut », en commençant par les composants de niveau inférieur (tels que `ProductRow`). Dans des contextes simples, il est généralement plus facile de procéder de haut en bas, et sur les projets plus complexes, il est plus aisé de procéder de bas en haut. @@ -239,7 +239,7 @@ Au bout du compte, seuls le texte de la recherche et l'état de la case à coche #### Props vs. état {/*props-vs-state*/} -React propose deux types de données de « modèle » : les props et l'état. Les deux diffèrent drastiquement : +React propose deux types de données de « modèle » : les props et l'état. Ces deux types diffèrent de façon drastique : - [Les **props** sont comme des arguments que vous passez](/learn/passing-props-to-a-component) à une fonction. Elles permettent au composant parent de passer des données à un composant enfant et de personnaliser ainsi son apparence. Par exemple, un `Form` pourrait passer une prop `color` à un `Button`. - [L'**état** est comme la mémoire du composant](/learn/state-a-components-memory). Il permet au composant de garder trace de certaines informations et de les modifier en réaction à des interactions. Par exemple, un `Button` pourrait vouloir garder trace de son état `isHovered`. @@ -259,9 +259,9 @@ Pour chaque élément d'état de votre application : 3. Décidez où l'état devrait vivre : 1. Le plus souvent, vous pourrez mettre l'état directement dans leur ancêtre commun. 2. Vous pouvez aussi le mettre dans un composant au-dessus de leur ancêtre commun. - 3. Si vous ne trouverez aucun composant dans lequel il semble logique de placer l'état, créez un nouveau composant spécifiquement pour contenir l'état, et insérez-le dans l'arborescence juste au-dessus de leur ancêtre commun. + 3. Si vous ne trouvez aucun composant dans lequel il semble logique de placer l'état, créez un nouveau composant spécifiquement pour contenir l'état, et insérez-le dans l'arborescence juste au-dessus de leur ancêtre commun. -Lors de l'étape précédente, ous avez trouvé deux éléments d'état pour cette application : le texte de la recherche et l'état de la case à cocher. Dans notre exemple, ils apparaissent toujours ensemble, de sorte qu'il semble lorsque de les placer au même endroit. +Lors de l'étape précédente, vous avez trouvé deux éléments d'état pour cette application : le texte de la recherche et l'état de la case à cocher. Dans notre exemple, ils apparaissent toujours ensemble, de sorte qu'il semble logique de les placer au même endroit. Déroulons notre stratégie pour eux : @@ -441,7 +441,7 @@ Remarquez que la saisie dans le formulaire ne marche pas encore. On voit une er -You provided a \`value\` prop to a form field without an \`onChange\` handler. This will render a read-only field. +You provided a \`value\` prop to a form field without an \`onChange\` handler. This will render a read-only field. […] @@ -465,9 +465,9 @@ Cependant, vous n'avez pas encore ajouté de code pour réagir aux actions de l' Pour le moment, votre appli s'affiche correctement avec les props et l'état qui circulent le long de son arborescence. Mais pour modifier l'état suite à des saisies utilisateur, vous allez devoir permettre un flux de données dans l'autre sens : les composants de formulaire enfouis dans l'arbre vont avoir besoin de mettre à jour l'état de `FilterableProductTable`. -React impose que ce flux de données soit explicite, ce qui nécessite un peu plus de frappe que les liaisons de données bidirectionnelles. Si vous essayez de saisir quelque chose dans la recherche, ou de cocher la case dans l'exemple ci-dessus, vous verrez que React ignore vos saisies. C'est voulu. En écrivant ``, vous avez calé la prop `value` de l'`input` pour qu'elle reflète toujours l'état `filterText` passé depuis `FilterableProductTable`. Puisque l'état `filterText` n'est jamais modifié, le champ ne change jamais de valeur. +React impose que ce flux de données soit explicite, ce qui nécessite un peu plus de code qu'avec des liaisons de données bidirectionnelles. Si vous essayez de saisir quelque chose dans la recherche, ou de cocher la case dans l'exemple ci-dessus, vous verrez que React ignore vos saisies. C'est voulu. En écrivant ``, vous avez calé la prop `value` de l'`input` pour qu'elle reflète toujours l'état `filterText` passé depuis `FilterableProductTable`. Puisque l'état `filterText` n'est jamais modifié, le champ ne change jamais de valeur. -Vous souhaitez que chaque fois que l'utilisateur modifie les champs du formulaire, l'état soit mis à jour pour refléter ces changements. L'état appartient à `FilterableProductTable`, de sorte que seul ce composant peut appeler `setFilterText` et `setInStockOnly`. Pour permettre à `SearchBar` de mettre à jour l'état de `FilterableProductTable`, vous allez devoir lui passer des fonctions `SearchBar` : +Vous souhaitez que chaque fois que l'utilisateur modifie les champs du formulaire, l'état soit mis à jour pour refléter ces changements. L'état appartient à `FilterableProductTable`, de sorte que seul ce composant peut appeler `setFilterText` et `setInStockOnly`. Pour permettre à `SearchBar` de mettre à jour l'état de `FilterableProductTable`, vous allez devoir passer des fonctions à `SearchBar` : ```js {2,3,10,11} function FilterableProductTable({ products }) { @@ -483,7 +483,7 @@ function FilterableProductTable({ products }) { onInStockOnlyChange={setInStockOnly} /> ``` -Au sein de `Searchbar`, ajoutez des gestionnaires d'événements `onChange` et utilisez-les pour modifier l'état du parent : +Au sein de `SearchBar`, ajoutez des gestionnaires d'événements `onChange` à vos champs et utilisez-les pour modifier l'état du parent : ```js {5} Date: Wed, 5 Jul 2023 18:28:39 +0200 Subject: [PATCH 3/3] chore(thinking-in-react): update translators manifests --- TRANSLATORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/TRANSLATORS.md b/TRANSLATORS.md index 86b7455a4..808779445 100644 --- a/TRANSLATORS.md +++ b/TRANSLATORS.md @@ -60,6 +60,7 @@ Voici la liste par ordre alphabétique (prénom, nom). **🙏🏻 Mille mercis
NamePriceNomPrix