From 6593e7d6428c4a830331a4f801d3e221da2476b5 Mon Sep 17 00:00:00 2001 From: Christophe Porteneuve Date: Tue, 11 Jul 2023 15:07:44 +0200 Subject: [PATCH 1/9] copy(useEffect): first part (until Usage) --- src/content/reference/react/useEffect.md | 66 ++++++++++++------------ 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/src/content/reference/react/useEffect.md b/src/content/reference/react/useEffect.md index 8d04f205c..0260dc670 100644 --- a/src/content/reference/react/useEffect.md +++ b/src/content/reference/react/useEffect.md @@ -4,7 +4,7 @@ title: useEffect -`useEffect` is a React Hook that lets you [synchronize a component with an external system.](/learn/synchronizing-with-effects) +`useEffect` est un Hook React qui vous permet de [synchroniser un composant avec un système extérieur](/learn/synchronizing-with-effects). ```js useEffect(setup, dependencies?) @@ -16,11 +16,11 @@ useEffect(setup, dependencies?) --- -## Reference {/*reference*/} +## Référence {/*reference*/} ### `useEffect(setup, dependencies?)` {/*useeffect*/} -Call `useEffect` at the top level of your component to declare an Effect: +Appelez `useEffect` à la racine de votre composant pour déclarer un Effet : ```js import { useEffect } from 'react'; @@ -40,39 +40,39 @@ function ChatRoom({ roomId }) { } ``` -[See more examples below.](#usage) +[Voir d'autres exemples ci-dessous](#usage). -#### Parameters {/*parameters*/} +#### Paramètres {/*parameters*/} -* `setup`: The function with your Effect's logic. Your setup function may also optionally return a *cleanup* function. When your component is added to the DOM, React will run your setup function. After every re-render with changed dependencies, React will first run the cleanup function (if you provided it) with the old values, and then run your setup function with the new values. After your component is removed from the DOM, React will run your cleanup function. - -* **optional** `dependencies`: The list of all reactive values referenced inside of the `setup` code. Reactive values include props, state, and all the variables and functions declared directly inside your component body. If your linter is [configured for React](/learn/editor-setup#linting), it will verify that every reactive value is correctly specified as a dependency. The list of dependencies must have a constant number of items and be written inline like `[dep1, dep2, dep3]`. React will compare each dependency with its previous value using the [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) comparison. If you omit this argument, your Effect will re-run after every re-render of the component. [See the difference between passing an array of dependencies, an empty array, and no dependencies at all.](#examples-dependencies) +* `setup` : la fonction contenant la logique de votre Effet. Votre fonctino de mise en place peut par ailleurs renvoyer une fonction de *nettoyage*. Quand votre composant est ajouté au DOM, React exécutera votre fonction de mise en place. Après chaque nouveau rendu dont les dépendances ont changé, React commencera par exécuter votre fonction de nettoyage (si vous en avez fourni une) avec les anciennes valeurs, puis exécutera votre fonction de mise en place avec les nouvelles valeurs. Une fois votre composant retiré du DOM, React exécutera votre fonction de nettoyage. -#### Returns {/*returns*/} +* `dependencies` **optionnelles** : la liste des valeurs réactives référencées par le code de `setup`. Les valeurs réactives comprennent les props, les variables d'état et toutes les variables et fonctions déclarées localement dans le corps de votre composant. Si votre *linter* est [configuré pour React](/learn/editor-setup#linting), il vérifiera que chaque valeur réactive concernée est bien spécifiée comme dépendance. La liste des dépendances doit avoir un nombre constant d'éléments et utiliser un littéral défini à la volée, du genre `[dep1, dep2, dep3]`. React comparera chaque dépendance à sa valeur précédente au moyen de la comparaison [`Object.is`](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/Object/is). Si vous omettez cet argument, votre Effet sera re-exécuté après chaque rendu du composant. [Découvrez la différence entre passer un tableau de dépendances, un tableau vide ou aucun tableau](#examples-dependencies). -`useEffect` returns `undefined`. +#### Valeur renvoyée {/*returns*/} -#### Caveats {/*caveats*/} +`useEffect` renvoie `undefined`. -* `useEffect` is a Hook, so you can only call it **at the top level of your component** or your own Hooks. You can't call it inside loops or conditions. If you need that, extract a new component and move the state into it. +#### Limitations {/*caveats*/} -* If you're **not trying to synchronize with some external system,** [you probably don't need an Effect.](/learn/you-might-not-need-an-effect) +* `useEffect` est un Hook, vous pouvez donc uniquement l’appeler **à la racine de votre composant** ou de vos propres Hooks. Vous ne pouvez pas l’appeler à l’intérieur de boucles ou de conditions. Si nécessaire, extrayez un nouveau composant et déplacez l'état dans celui-ci. -* When Strict Mode is on, React will **run one extra development-only setup+cleanup cycle** before the first real setup. This is a stress-test that ensures that your cleanup logic "mirrors" your setup logic and that it stops or undoes whatever the setup is doing. If this causes a problem, [implement the cleanup function.](/learn/synchronizing-with-effects#how-to-handle-the-effect-firing-twice-in-development) +* Si vous **ne cherchez pas à synchroniser avec un système extérieur**, [vous n'avez probablement pas besoin d'un Effet](/learn/you-might-not-need-an-effect). -* If some of your dependencies are objects or functions defined inside the component, there is a risk that they will **cause the Effect to re-run more often than needed.** To fix this, remove unnecessary [object](#removing-unnecessary-object-dependencies) and [function](#removing-unnecessary-function-dependencies) dependencies. You can also [extract state updates](#updating-state-based-on-previous-state-from-an-effect) and [non-reactive logic](#reading-the-latest-props-and-state-from-an-effect) outside of your Effect. +* Quand le mode strict est activé, React **appellera une fois de plus votre cycle mise en place + nettoyage, uniquement en développement**, avant la première mise en place réelle. C'est une mise à l'épreuve pour vérifier que votre logique de nettoyage reflète bien votre logique de mise en place, et décommissionne ou défait toute la mise en place effectuée. Si ça entraîne des problèmes, [écrivez une fonction de nettoyage](/learn/synchronizing-with-effects#how-to-handle-the-effect-firing-twice-in-development). -* If your Effect wasn't caused by an interaction (like a click), React will let the browser **paint the updated screen first before running your Effect.** If your Effect is doing something visual (for example, positioning a tooltip), and the delay is noticeable (for example, it flickers), replace `useEffect` with [`useLayoutEffect`.](/reference/react/useLayoutEffect) +* Si certaines de vos dépendances sont des objets ou fonctions définies au sein de votre composant, il existe un risque qu'elles **entraînent des exécutions superflues de votre Effet**. Pour corriger ça, retirez les dépendances superflues sur des [objets](#removing-unnecessary-object-dependencies) et [fonctions](#removing-unnecessary-function-dependencies). Vous pouvez aussi [extraire les mises à jour d'état](#updating-state-based-on-previous-state-from-an-effect) et la [logique non réactive](#reading-the-latest-props-and-state-from-an-effect) hors de votre Effet. -* Even if your Effect was caused by an interaction (like a click), **the browser may repaint the screen before processing the state updates inside your Effect.** Usually, that's what you want. However, if you must block the browser from repainting the screen, you need to replace `useEffect` with [`useLayoutEffect`.](/reference/react/useLayoutEffect) +* Si votre Effet ne découlait pas d'une interaction (telle qu'un clic), React laissera le navigateur **rafraîchir l'affichage à l'écran avant d'exécuter votre Effet**. Si votre Effet a des aspects visuels (par exemple, il positionne une infobulle) et que le retard est perceptible (par exemple, l'affichage est intermittent), remplacez `useEffect` par `useLayoutEffect`(/reference/react/useLayoutEffect). -* Effects **only run on the client.** They don't run during server rendering. +* Même si votre Effet est déclenché par une interaction (telle qu'un clic), **le navigateur est susceptible de rafraîchir l'affichage avant d'avoir traité les mises à jour d'état au sein de votre Effet**. C'est généralement ce que vous souhaitez. Cependant, si vous devez empêcher le navigateur de rafraîchir l'affichage tout de suite, remplacez `useEffect` par [`useLayoutEffect`](/reference/react/useLayoutEffect). + +* Les Effets **ne sont exécutés que côté client**. Ils sont ignorés lors du rendu côté serveur. --- -## Usage {/*usage*/} +## Utilisation {/*usage*/} -### Connecting to an external system {/*connecting-to-an-external-system*/} +### Connexion à un système extérieur {/*connecting-to-an-external-system*/} Some components need to stay connected to the network, some browser API, or a third-party library, while they are displayed on the page. These systems aren't controlled by React, so they are called *external.* @@ -110,7 +110,7 @@ You need to pass two arguments to `useEffect`: - Then, your setup code runs with the new props and state. 3. Your cleanup code runs one final time after your component is removed from the page *(unmounts).* -**Let's illustrate this sequence for the example above.** +**Let's illustrate this sequence for the example above.** When the `ChatRoom` component above gets added to the page, it will connect to the chat room with the initial `serverUrl` and `roomId`. If either `serverUrl` or `roomId` change as a result of a re-render (say, if the user picks a different chat room in a dropdown), your Effect will *disconnect from the previous room, and connect to the next one.* When the `ChatRoom` component is removed from the page, your Effect will disconnect one last time. @@ -500,7 +500,7 @@ export default function Box() { --- -### Wrapping Effects in custom Hooks {/*wrapping-effects-in-custom-hooks*/} +### Enrober vos Effets dans des Hooks personnalisés {/*wrapping-effects-in-custom-hooks*/} Effects are an ["escape hatch":](/learn/escape-hatches) you use them when you need to "step outside React" and when there is no better built-in solution for your use case. If you find yourself often needing to manually write Effects, it's usually a sign that you need to extract some [custom Hooks](/learn/reusing-logic-with-custom-hooks) for common behaviors your components rely on. @@ -784,7 +784,7 @@ export function useIntersectionObserver(ref) { --- -### Controlling a non-React widget {/*controlling-a-non-react-widget*/} +### Contrôler un widget non géré par React {/*controlling-a-non-react-widget*/} Sometimes, you want to keep an external system synchronized to some prop or state of your component. @@ -892,7 +892,7 @@ In this example, a cleanup function is not needed because the `MapWidget` class --- -### Fetching data with Effects {/*fetching-data-with-effects*/} +### Charger des données avec les Effets {/*fetching-data-with-effects*/} You can use an Effect to fetch data for your component. Note that [if you use a framework,](/learn/start-a-new-react-project#production-grade-react-frameworks) using your framework's data fetching mechanism will be a lot more efficient than writing Effects manually. @@ -1055,7 +1055,7 @@ You can continue fetching data directly in Effects if neither of these approache --- -### Specifying reactive dependencies {/*specifying-reactive-dependencies*/} +### Spécifier les dépendances réactives {/*specifying-reactive-dependencies*/} **Notice that you can't "choose" the dependencies of your Effect.** Every reactive value used by your Effect's code must be declared as a dependency. Your Effect's dependency list is determined by the surrounding code: @@ -1079,7 +1079,7 @@ If either `serverUrl` or `roomId` change, your Effect will reconnect to the chat ```js {8} function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); - + useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); @@ -1415,7 +1415,7 @@ button { margin-left: 5px; } --- -### Updating state based on previous state from an Effect {/*updating-state-based-on-previous-state-from-an-effect*/} +### Mettre à jour l'état sur base d'un état précédent, au sein d'un Effet {/*updating-state-based-on-previous-state-from-an-effect*/} When you want to update state based on previous state from an Effect, you might run into a problem: @@ -1433,7 +1433,7 @@ function Counter() { } ``` -Since `count` is a reactive value, it must be specified in the list of dependencies. However, that causes the Effect to cleanup and setup again every time the `count` changes. This is not ideal. +Since `count` is a reactive value, it must be specified in the list of dependencies. However, that causes the Effect to cleanup and setup again every time the `count` changes. This is not ideal. To fix this, [pass the `c => c + 1` state updater](/reference/react/useState#updating-state-based-on-the-previous-state) to `setCount`: @@ -1475,7 +1475,7 @@ Now that you're passing `c => c + 1` instead of `count + 1`, [your Effect no lon --- -### Removing unnecessary object dependencies {/*removing-unnecessary-object-dependencies*/} +### Supprimer des dépendances objets superflues {/*removing-unnecessary-object-dependencies*/} If your Effect depends on an object or a function created during rendering, it might run too often. For example, this Effect re-connects after every render because the `options` object is [different for every render:](/learn/removing-effect-dependencies#does-some-reactive-value-change-unintentionally) @@ -1578,7 +1578,7 @@ With this fix, typing into the input doesn't reconnect the chat. Unlike an objec --- -### Removing unnecessary function dependencies {/*removing-unnecessary-function-dependencies*/} +### Supprimer des dépendances fonctions superflues {/*removing-unnecessary-function-dependencies*/} If your Effect depends on an object or a function created during rendering, it might run too often. For example, this Effect re-connects after every render because the `createOptions` function is [different for every render:](/learn/removing-effect-dependencies#does-some-reactive-value-change-unintentionally) @@ -1686,7 +1686,7 @@ Now that you define the `createOptions` function inside the Effect, the Effect i --- -### Reading the latest props and state from an Effect {/*reading-the-latest-props-and-state-from-an-effect*/} +### Lire les dernières props et états à jour depuis un Effet {/*reading-the-latest-props-and-state-from-an-effect*/} @@ -1729,7 +1729,7 @@ function Page({ url, shoppingCart }) { --- -### Displaying different content on the server and the client {/*displaying-different-content-on-the-server-and-the-client*/} +### Afficher un contenu différent côté serveur et côté client {/*displaying-different-content-on-the-server-and-the-client*/} If your app uses server rendering (either [directly](/reference/react-dom/server) or via a [framework](/learn/start-a-new-react-project#production-grade-react-frameworks)), your component will render in two different environments. On the server, it will render to produce the initial HTML. On the client, React will run the rendering code again so that it can attach your event handlers to that HTML. This is why, for [hydration](/reference/react-dom/client/hydrateRoot#hydrating-server-rendered-html) to work, your initial render output must be identical on the client and the server. @@ -1757,7 +1757,7 @@ Use this pattern sparingly. Keep in mind that users with a slow connection will --- -## Troubleshooting {/*troubleshooting*/} +## Dépannage {/*troubleshooting*/} ### My Effect runs twice when the component mounts {/*my-effect-runs-twice-when-the-component-mounts*/} From fcef9b81effa61a7c35654ce686c5269b2e45fec Mon Sep 17 00:00:00 2001 From: Christophe Porteneuve Date: Tue, 11 Jul 2023 16:33:31 +0200 Subject: [PATCH 2/9] copy(useEffect): translate usage "connect" subsection --- src/content/reference/react/useEffect.md | 178 ++++++++++++----------- 1 file changed, 90 insertions(+), 88 deletions(-) diff --git a/src/content/reference/react/useEffect.md b/src/content/reference/react/useEffect.md index 0260dc670..80e5d9031 100644 --- a/src/content/reference/react/useEffect.md +++ b/src/content/reference/react/useEffect.md @@ -72,11 +72,11 @@ function ChatRoom({ roomId }) { ## Utilisation {/*usage*/} -### Connexion à un système extérieur {/*connecting-to-an-external-system*/} +### Se connecter à un système extérieur {/*connecting-to-an-external-system*/} -Some components need to stay connected to the network, some browser API, or a third-party library, while they are displayed on the page. These systems aren't controlled by React, so they are called *external.* +Certains composants ont besoin de rester connectés au réseau, ou à des API du navigateur, ou à des bibliothèques tierces, tout le temps qu'ils sont à l'écran. Ces systèmes ne sont pas gérés par React, on les qualifie donc de systèmes *extérieurs*. -To [connect your component to some external system,](/learn/synchronizing-with-effects) call `useEffect` at the top level of your component: +Pour [connecter votre composant à un système extérieur](/learn/synchronizing-with-effects), appelez `useEffect` au niveau racine de votre composant : ```js [[1, 8, "const connection = createConnection(serverUrl, roomId);"], [1, 9, "connection.connect();"], [2, 11, "connection.disconnect();"], [3, 13, "[serverUrl, roomId]"]] import { useEffect } from 'react'; @@ -86,55 +86,55 @@ function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); useEffect(() => { - const connection = createConnection(serverUrl, roomId); + const connection = createConnection(serverUrl, roomId); connection.connect(); - return () => { + return () => { connection.disconnect(); - }; + }; }, [serverUrl, roomId]); // ... } ``` -You need to pass two arguments to `useEffect`: +Vous devez passer deux arguments à `useEffect` : -1. A *setup function* with setup code that connects to that system. - - It should return a *cleanup function* with cleanup code that disconnects from that system. -2. A list of dependencies including every value from your component used inside of those functions. +1. Une *fonction de mise en place* avec du code de mise en place qui vous connecte au système. + - Elle devrait renvoyer une *fonction de nettoyage* avec du code de nettoyage qui vous déconnecte du système. +2. Une liste de dépendances comprenant chaque valeur issue de votre composant que ces fonctions utilisent. -**React calls your setup and cleanup functions whenever it's necessary, which may happen multiple times:** +**React appellera vos fonctions de mise en place et de nettoyage chaque fois que nécessaire, ce qui peut survenir plusieurs fois :** -1. Your setup code runs when your component is added to the page *(mounts)*. -2. After every re-render of your component where the dependencies have changed: - - First, your cleanup code runs with the old props and state. - - Then, your setup code runs with the new props and state. -3. Your cleanup code runs one final time after your component is removed from the page *(unmounts).* +1. Votre code de mise en place est exécuté quand votre composant est ajouté à la page *(montage)*. +2. Après chaque nouveau rendu de votre composant, si les dépendances ont changé : + - D'abord, votre code de nettoyage est exécuté avec les anciennes props et états. + - Ensuite, votre code de mise en place est exécuté avec les nouvelles props et états. +3. Votre code de nettoyage est exécuté une dernière fois lorsque votre composant est retiré de la page *(démontage)*. -**Let's illustrate this sequence for the example above.** +**Illustrons cette séquence pour l'exemple ci-avant.** -When the `ChatRoom` component above gets added to the page, it will connect to the chat room with the initial `serverUrl` and `roomId`. If either `serverUrl` or `roomId` change as a result of a re-render (say, if the user picks a different chat room in a dropdown), your Effect will *disconnect from the previous room, and connect to the next one.* When the `ChatRoom` component is removed from the page, your Effect will disconnect one last time. +Lorsque le composant `ChatRoom` ci-dessus sera ajouté à la page, il se connectera au salon de discussion en utilisant les valeurs initiales de `serverUrl` et `roomId`. Si l'une ou l'autre de ces deux valeurs change suite à un nouveau rendu (peut-être l'utilisateur a-t-il choisi un autre salon dans la liste déroulante), votre Effet *se déconnectera du salon précédent, puis se connecter au nouveau salon*. Lorsque le composant `ChatRoom` sera retiré de la page, votre Effet se déconnectera une dernière fois. -**To [help you find bugs,](/learn/synchronizing-with-effects#step-3-add-cleanup-if-needed) in development React runs setup and cleanup one extra time before the setup.** This is a stress-test that verifies your Effect's logic is implemented correctly. If this causes visible issues, your cleanup function is missing some logic. The cleanup function should stop or undo whatever the setup function was doing. The rule of thumb is that the user shouldn't be able to distinguish between the setup being called once (as in production) and a *setup* → *cleanup* → *setup* sequence (as in development). [See common solutions.](/learn/synchronizing-with-effects#how-to-handle-the-effect-firing-twice-in-development) +**Pour [vous aider à repérer des bugs](/learn/synchronizing-with-effects#step-3-add-cleanup-if-needed), en développement React exécutera un premier cycle de mise en place et de nettoyage, avant d'exécuter normalement la mise en place nominale.** C'est une mise à l'épreuve pour vérifier que la logique de votre Effet est implémentée correctement. Si ça entraîne des problèmes, c'est que votre code de nettoyage est manquant ou incomplet. La fonction de nettoyage devrait arrêter ou défaire ce que la fonction de mise en place a initié. La règle à suivre est simple : l'utilisateur ne devrait pas pouvoir faire la différence entre une exécution unique de la mise en place (comme en production) et une séquence *mise en place* → *nettoyage* → *mise en place* (comme en développement). [Explorez les solutions courantes](/learn/synchronizing-with-effects#how-to-handle-the-effect-firing-twice-in-development). -**Try to [write every Effect as an independent process](/learn/lifecycle-of-reactive-effects#each-effect-represents-a-separate-synchronization-process) and [think about a single setup/cleanup cycle at a time.](/learn/lifecycle-of-reactive-effects#thinking-from-the-effects-perspective)** It shouldn't matter whether your component is mounting, updating, or unmounting. When your cleanup logic correctly "mirrors" the setup logic, your Effect is resilient to running setup and cleanup as often as needed. +**Essayez [d'écrire chaque Effet comme un processus autonome](/learn/lifecycle-of-reactive-effects#each-effect-represents-a-separate-synchronization-process) et de [réfléchir à un seul cycle de mise en place / nettoyage à la fois](/learn/lifecycle-of-reactive-effects#thinking-from-the-effects-perspective).** Le fait que votre composant soit en train d'être monté, de se mettre à jour ou d'être démonté ne devrait avoir aucune importance. Lorsque votre logique de nettoyage reflète correctement celle de mise en place, votre Effet n'aura aucun problème avec des exécutions multiples de la mise en place et du nettoyage. -An Effect lets you [keep your component synchronized](/learn/synchronizing-with-effects) with some external system (like a chat service). Here, *external system* means any piece of code that's not controlled by React, such as: +Un Effet vous permet de [garder votre composant synchronisé](/learn/synchronizing-with-effects) avec un système extérieur (tels qu'un service de discussion). Dans ce contexte, *système extérieur* désigne n'importe quel bout de code qui n'est pas géré par React, par exemple : -* A timer managed with [`setInterval()`](https://developer.mozilla.org/en-US/docs/Web/API/setInterval) and [`clearInterval()`](https://developer.mozilla.org/en-US/docs/Web/API/clearInterval). -* An event subscription using [`window.addEventListener()`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener) and [`window.removeEventListener()`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener). -* A third-party animation library with an API like `animation.start()` and `animation.reset()`. +* Un timer géré par [`setInterval()`](https://developer.mozilla.org/en-US/docs/Web/API/setInterval) et [`clearInterval()`](https://developer.mozilla.org/fr/docs/Web/API/clearInterval). +* Un abonnement sur événement grâce à [`window.addEventListener()`](https://developer.mozilla.org/fr/docs/Web/API/EventTarget/addEventListener) et [`window.removeEventListener()`](https://developer.mozilla.org/fr/docs/Web/API/EventTarget/removeEventListener). +* Une bibliothèque d'animations tierce avec une API du genre `animation.start()` et `animation.reset()`. -**If you're not connecting to any external system, [you probably don't need an Effect.](/learn/you-might-not-need-an-effect)** +**Si vous ne vous connectez pas à un système extérieur, [vous n'avez sans doute pas besoin d'un Effet](/learn/you-might-not-need-an-effect).** - + -#### Connecting to a chat server {/*connecting-to-a-chat-server*/} +#### Se connecter à un serveur de discussion {/*connecting-to-a-chat-server*/} -In this example, the `ChatRoom` component uses an Effect to stay connected to an external system defined in `chat.js`. Press "Open chat" to make the `ChatRoom` component appear. This sandbox runs in development mode, so there is an extra connect-and-disconnect cycle, as [explained here.](/learn/synchronizing-with-effects#step-3-add-cleanup-if-needed) Try changing the `roomId` and `serverUrl` using the dropdown and the input, and see how the Effect re-connects to the chat. Press "Close chat" to see the Effect disconnect one last time. +Dans cet exemple, le composant `ChatRoom` utilise un Effet pour rester connecté à un système extérieur défini dans `chat.js`. Appuyez sur « Ouvrir le salon » pour que le composant `ChatRoom` apparaisse. Ce bac à sable est en mode développement, il y aura donc un cycle supplémentaire de connexion-déconnexion, comme [expliqué ici](/learn/synchronizing-with-effects#step-3-add-cleanup-if-needed). Essayez de changer `roomId` et `serverUrl` en utilisant la liste déroulante et le champ de saisie, et voyez comme l'Effet se reconnecte au salon. Appuyez sur « Fermer le salon » pour vous déconnecter une dernière fois. @@ -156,13 +156,13 @@ function ChatRoom({ roomId }) { return ( <> -

Welcome to the {roomId} room!

+

Bienvenue dans le salon {roomId} !

); } @@ -173,18 +173,18 @@ export default function App() { return ( <> {show &&
} {show && } @@ -195,13 +195,13 @@ export default function App() { ```js chat.js export function createConnection(serverUrl, roomId) { - // A real implementation would actually connect to the server + // Une véritable implémentation se connecterait en vrai au serveur return { connect() { - console.log('✅ Connecting to "' + roomId + '" room at ' + serverUrl + '...'); + console.log('✅ Connexion au salon « ' + roomId + ' » sur ' + serverUrl + '...'); }, disconnect() { - console.log('❌ Disconnected from "' + roomId + '" room at ' + serverUrl); + console.log('❌ Déconnexion du salon « ' + roomId + ' » sur ' + serverUrl); } }; } @@ -216,9 +216,9 @@ button { margin-left: 10px; } -#### Listening to a global browser event {/*listening-to-a-global-browser-event*/} +#### Écouter un événement global du navigateur {/*listening-to-a-global-browser-event*/} -In this example, the external system is the browser DOM itself. Normally, you'd specify event listeners with JSX, but you can't listen to the global [`window`](https://developer.mozilla.org/en-US/docs/Web/API/Window) object this way. An Effect lets you connect to the `window` object and listen to its events. Listening to the `pointermove` event lets you track the cursor (or finger) position and update the red dot to move with it. +Dans cet exemple, le système extérieur est le DOM navigateur lui-même. En temps normal, vous définiriez des gestionnaires d'événements en JSX, mais vous ne pouvez pas écouter des événements de l'objet global [`window`](https://developer.mozilla.org/fr/docs/Web/API/Window) de cette façon. Un Effet vous permet de vous connecter à l'objet `window` et d'écouter ses événements. En vous abonnant à l'événement `pointermove`, vous pouvez surveiller la position du curseur (ou du doigt) et mettre à jour le point rouge pour bouger avec lui. @@ -265,9 +265,9 @@ body { -#### Triggering an animation {/*triggering-an-animation*/} +#### Déclencher une animation {/*triggering-an-animation*/} -In this example, the external system is the animation library in `animation.js`. It provides a JavaScript class called `FadeInAnimation` that takes a DOM node as an argument and exposes `start()` and `stop()` methods to control the animation. This component [uses a ref](/learn/manipulating-the-dom-with-refs) to access the underlying DOM node. The Effect reads the DOM node from the ref and automatically starts the animation for that node when the component appears. +Dans cet exemple, le système extérieur est la bibliothèque d'animation dans `animation.js`. Elle fournit une classe JavaScript appelée `FadeInAnimation` qui prend un nœud DOM comme argument et expose des méthodes `start()` et `stop()` pour contrôler l'animation. Ce composant [utilise une ref](/learn/manipulating-the-dom-with-refs) pour accéder au nœud DOM sous-jacent. L'Effet lit le nœud DOM depuis la ref et démarre automatiquement l'animation pour ce nœud lorsque le composant apparaît. @@ -298,7 +298,7 @@ function Welcome() { backgroundImage: 'radial-gradient(circle, rgba(63,94,251,1) 0%, rgba(252,70,107,1) 100%)' }} > - Welcome + Bienvenue ); } @@ -308,7 +308,7 @@ export default function App() { return ( <>
{show && } @@ -325,11 +325,11 @@ export class FadeInAnimation { start(duration) { this.duration = duration; if (this.duration === 0) { - // Jump to end immediately + // Sauter à la fin this.onProgress(1); } else { this.onProgress(0); - // Start animating + // Commencer l'animation this.startTime = performance.now(); this.frameId = requestAnimationFrame(() => this.onFrame()); } @@ -339,7 +339,7 @@ export class FadeInAnimation { const progress = Math.min(timePassed / this.duration, 1); this.onProgress(progress); if (progress < 1) { - // We still have more frames to paint + // Il nous reste des étapes à afficher this.frameId = requestAnimationFrame(() => this.onFrame()); } } @@ -364,9 +364,9 @@ html, body { min-height: 300px; } -#### Controlling a modal dialog {/*controlling-a-modal-dialog*/} +#### Contrôler une boîte de dialogue modale {/*controlling-a-modal-dialog*/} -In this example, the external system is the browser DOM. The `ModalDialog` component renders a [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog) element. It uses an Effect to synchronize the `isOpen` prop to the [`showModal()`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement/showModal) and [`close()`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement/close) method calls. +Dans cet exemple, le système extérieur est le DOM navigateur. Le composant `ModalDialog` utilise un élément [``](https://developer.mozilla.org/fr/docs/Web/HTML/Element/dialog). Il utilise un Effet pour synchroniser la prop `isOpen` avec les appels aux méthodes [`'showModal()'](https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement/showModal) et [`close()`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement/close). @@ -379,14 +379,14 @@ export default function App() { return ( <> - Hello there! + Salut !
+ }}>Fermer
); @@ -424,9 +424,9 @@ body { -#### Tracking element visibility {/*tracking-element-visibility*/} +#### Surveiller la visibilité d'un élément {/*tracking-element-visibility*/} -In this example, the external system is again the browser DOM. The `App` component displays a long list, then a `Box` component, and then another long list. Scroll the list down. Notice that when the `Box` component appears in the viewport, the background color changes to black. To implement this, the `Box` component uses an Effect to manage an [`IntersectionObserver`](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API). This browser API notifies you when the DOM element is visible in the viewport. +Dans cet exemple, le système extérieur est encore le DOM navigateur. Le composant `App` affiche une longue liste, puis un composant `Box`, puis une autre longue liste. Faites défiler la liste. Voyez comment, lorsque le composant `Box` apparaît à l'écran, la couleur de fond passe au noir. Pour implémenter ça, le composant `Box` utilise un Effet pour gérer un [`IntersectionObserver`](https://developer.mozilla.org/fr/docs/Web/API/Intersection_Observer_API). Cette API navigateur vous notifie lorsque l'élément DOM est visible dans la zone de rendu de la fenêtre. @@ -448,7 +448,7 @@ export default function App() { function LongSection() { const items = []; for (let i = 0; i < 50; i++) { - items.push(
  • Item #{i} (keep scrolling)
  • ); + items.push(
  • Élément #{i} (continuez à défiler)
  • ); } return
      {items}
    } @@ -502,6 +502,8 @@ export default function Box() { ### Enrober vos Effets dans des Hooks personnalisés {/*wrapping-effects-in-custom-hooks*/} + + Effects are an ["escape hatch":](/learn/escape-hatches) you use them when you need to "step outside React" and when there is no better built-in solution for your use case. If you find yourself often needing to manually write Effects, it's usually a sign that you need to extract some [custom Hooks](/learn/reusing-logic-with-custom-hooks) for common behaviors your components rely on. For example, this `useChatRoom` custom Hook "hides" the logic of your Effect behind a more declarative API: @@ -560,13 +562,13 @@ function ChatRoom({ roomId }) { return ( <> -

    Welcome to the {roomId} room!

    +

    Bienvenue dans le salon {roomId} !

    ); } @@ -577,18 +579,18 @@ export default function App() { return ( <> {show &&
    } {show && } @@ -1173,13 +1175,13 @@ function ChatRoom({ roomId }) { return ( <> -

    Welcome to the {roomId} room!

    +

    Bienvenue dans le salon {roomId} !

    -Par défaut, lorsque vous lisez une valeur réactive depuis un Effet, vous devez l'ajouter comme dépendance. Ça garantir que votre Effet « réagit » à chaque modification de cette valeur. Pour la plupart des dépendances, c'est bien le comportement que vous souhaitez. +Par défaut, lorsque vous lisez une valeur réactive depuis un Effet, vous devez l'ajouter comme dépendance. Ça garantit que votre Effet « réagit » à chaque modification de cette valeur. Pour la plupart des dépendances, c'est bien le comportement que vous souhaitez. **Toutefois, il peut arriver que vous souhaitiez lire les *dernières* valeurs à jour de props ou d'états depuis un Effet, sans pour autant y « réagir ».** Imaginons par exemple que vous souhaitiez afficher en console le nombre d'éléments dans le panier d'achats à chaque visite de la page : @@ -1709,7 +1709,7 @@ function Page({ url, shoppingCart }) { } ``` -**Et si vous vouliez afficher une visite de page après chaque modification de `url`, mais *pas* lorsque seul `shoppingCart` change ?** Vous ne pouvez pas exclure `shoppingCart` de vos dépendances sans enfreindre les [règles de la réactivité](#specifying-reactive-dependencies). En revanche, vous pouvez exprimer que vous *ne souhaitez pas* qu'un bout de votre code « réagisse » aux changemeents, même s'il est appelé depuis un Effet. [Déclarez un *Événement d'Effet*](/learn/separating-events-from-effects#declaring-an-effect-event) avec le Hook [`useEffectEvent`](/reference/react/experimental_useEffectEvent), et déplacez le code qui consulte `shoppingCart` à l'intérieur : +**Et si vous vouliez afficher une visite de page après chaque modification de `url`, mais *pas* lorsque seul `shoppingCart` change ?** Vous ne pouvez pas exclure `shoppingCart` de vos dépendances sans enfreindre les [règles de la réactivité](#specifying-reactive-dependencies). En revanche, vous pouvez exprimer que vous *ne souhaitez pas* qu'un bout de votre code « réagisse » aux changements, même s'il est appelé depuis un Effet. [Déclarez un *Événement d'Effet*](/learn/separating-events-from-effects#declaring-an-effect-event) avec le Hook [`useEffectEvent`](/reference/react/experimental_useEffectEvent), et déplacez le code qui consulte `shoppingCart` à l'intérieur : ```js {2-4,7,8} function Page({ url, shoppingCart }) { @@ -1753,7 +1753,7 @@ function MyComponent() { } ``` -Penant que l'appli charge, l'utilisateur voit le résultat du rendu initial. Puis, lorsqu'elle sera chargée et hydratée, votre Effet sera exécuté et définira `didMount` à `true`, ce qui déclenchera un nouveau rendu. On basculera alors sur le résultat de rendu pour le client seulement. Les Effets ne sont pas exécutés côté serveur, c'est pourquoi `didMount` resterait à `false` lors du rendu initial. +Pendant que l'appli charge, l'utilisateur voit le résultat du rendu initial. Puis, lorsqu'elle sera chargée et hydratée, votre Effet sera exécuté et définira `didMount` à `true`, ce qui déclenchera un nouveau rendu. On basculera alors sur le résultat de rendu pour le client seulement. Les Effets ne sont pas exécutés côté serveur, c'est pourquoi `didMount` resterait à `false` lors du rendu initial. N'abusez pas de cette astuce. Gardez à l'esprit que les utilisateurs avec des connexions lentes verront le contenu initial pendant un bon bout de temps — jusqu'à plusieurs secondes — et qu'il faudrait donc éviter d'appliquer au final des changements trop drastiques dans l'apparence de votre composant. Le plus souvent, vous pourrez éviter de recourir à cette approche en utilisant des affichages conditionnels *via* CSS. @@ -1808,7 +1808,7 @@ Lorsque vous aurez repéré la dépendance qui diffère d'un rendu à l'autre, v - [Supprimer des dépendances fonctions superflues](#removing-unnecessary-function-dependencies) - [Lire les dernières props et états à jour depuis un Effet](#reading-the-latest-props-and-state-from-an-effect) -En tout dernier recours (si aucune de ces approches n'a résolu le souci), enrobez la création de la dépendance avec [`useMemo`](/reference/react/useMemo#memoizing-a-dependency-of-another-hook) ou [`useCallback`](/reference/react/useCallback#preventing-an-effect-from-firing-too-often) (pour les fonctions). +En tout dernier recours (si aucune de ces approches n'a résolu le souci), enrobez la création de la dépendance avec [`useMemo`](/reference/react/useMemo#memoizing-a-dependency-of-another-hook) (ou [`useCallback`](/reference/react/useCallback#preventing-an-effect-from-firing-too-often) pour les fonctions). --- @@ -1823,7 +1823,7 @@ Avant de vous attaquer à la résolution de ce problème, demandez-vous si votre S'il n'y a pas de système extérieur, envisagez de [retirer carrément l'Effet](/learn/you-might-not-need-an-effect) pour simplifier votre logique. -Si vous vous synchronisez effectivement avec un système extérieur, réfléchissez aux conditions dans lesquelles votre Effet devrait mettre à jour l'état. Quelque chose a-t-il changé qui impacte le résultat visuel de votre composant ? Si vous devez surveiller certaines données inutilisées par le rendu, une [ref](/reference/react/useRef#referencing-a-value-with-a-ref) (qui ne redéclenche pas de rendu) serait peut-être plus appropriée. Vérifiez que votre Effet ne met pas à jour l'Effet (entraînant un nouveau rendu) plus que nécessaire. +Si vous vous synchronisez effectivement avec un système extérieur, réfléchissez aux conditions dans lesquelles votre Effet devrait mettre à jour l'état. Quelque chose a-t-il changé qui impacte le résultat visuel de votre composant ? Si vous devez surveiller certaines données inutilisées par le rendu, une [ref](/reference/react/useRef#referencing-a-value-with-a-ref) (qui ne redéclenche pas de rendu) serait peut-être plus appropriée. Vérifiez que votre Effet ne met pas à jour l'état (entraînant un nouveau rendu) plus que nécessaire. Pour finir, si votre Effet met à jour l'état au bon moment, mais qu'il y a tout de même une boucle, c'est sans doute parce que la mise à jour de l'état entraîne la modification d'une des dépendances de l'Effet. [Voyez comment déboguer les modifications de dépendances](#my-effect-runs-after-every-re-render). @@ -1831,9 +1831,9 @@ Pour finir, si votre Effet met à jour l'état au bon moment, mais qu'il y a tou ### Ma logique de nettoyage est exécutée alors que mon composant n'a pas été démonté {/*my-cleanup-logic-runs-even-though-my-component-didnt-unmount*/} -La fonction de nettoyage n'est pas exécutée seulement lors du démontage, mais avant chaque nouveau rendu dont les dépendances ont changé. Qui plus est, en développement, React [exécute la mise en place et le nettoyage une fois de plus juste avant le démontage du composant](#my-effect-runs-twice-when-the-component-mounts). +La fonction de nettoyage n'est pas exécutée seulement lors du démontage, mais avant chaque nouveau rendu dont les dépendances ont changé. Qui plus est, en développement, React [exécute la mise en place et le nettoyage une fois de plus juste après le montage du composant](#my-effect-runs-twice-when-the-component-mounts). -Si vous avez du code de nettoyage sans code de mise en place correspondant c'est généralement mauvaise signe : +Si vous avez du code de nettoyage qui ne correspond à aucun code de mise en place, c'est généralement mauvaise signe : ```js {2-5} useEffect(() => {