diff --git a/.env.production b/.env.production
index d25eb7dd4..e403f96b6 100644
--- a/.env.production
+++ b/.env.production
@@ -1 +1 @@
-NEXT_PUBLIC_GA_TRACKING_ID = 'UA-41298772-4'
\ No newline at end of file
+NEXT_PUBLIC_GA_TRACKING_ID = 'G-B1E83PJ3RT'
\ No newline at end of file
diff --git a/package.json b/package.json
index 472ef79c9..b5e07d70a 100644
--- a/package.json
+++ b/package.json
@@ -30,7 +30,6 @@
"classnames": "^2.2.6",
"date-fns": "^2.16.1",
"debounce": "^1.2.1",
- "ga-lite": "^2.1.4",
"github-slugger": "^1.3.0",
"next": "^13.4.1",
"next-remote-watch": "^1.0.0",
diff --git a/src/components/Layout/Feedback.tsx b/src/components/Layout/Feedback.tsx
index babef0993..b118e9ed7 100644
--- a/src/components/Layout/Feedback.tsx
+++ b/src/components/Layout/Feedback.tsx
@@ -4,7 +4,6 @@
import {useState} from 'react';
import {useRouter} from 'next/router';
-import {ga} from '../../utils/analytics';
export function Feedback({onSubmit = () => {}}: {onSubmit?: () => void}) {
const {asPath} = useRouter();
@@ -48,14 +47,12 @@ const thumbsDownIcon = (
function sendGAEvent(isPositive: boolean) {
// Fragile. Don't change unless you've tested the network payload
// and verified that the right events actually show up in GA.
- ga(
- 'send',
- 'event',
- 'button',
- 'feedback',
- window.location.pathname,
- isPositive ? '1' : '0'
- );
+ // @ts-ignore
+ gtag('event', 'feedback', {
+ event_category: 'button',
+ event_label: window.location.pathname,
+ value: isPositive ? 1 : 0,
+ });
}
function SendFeedback({onSubmit}: {onSubmit: () => void}) {
diff --git a/src/components/Layout/Page.tsx b/src/components/Layout/Page.tsx
index 5f2bc8f04..a823c189b 100644
--- a/src/components/Layout/Page.tsx
+++ b/src/components/Layout/Page.tsx
@@ -28,7 +28,12 @@ interface PageProps {
children: React.ReactNode;
toc: Array;
routeTree: RouteItem;
- meta: {title?: string; canary?: boolean; description?: string};
+ meta: {
+ title?: string;
+ titleForTitleTag?: string;
+ canary?: boolean;
+ description?: string;
+ };
section: 'learn' | 'reference' | 'community' | 'blog' | 'home' | 'unknown';
}
@@ -107,6 +112,7 @@ export function Page({children, toc, routeTree, meta, section}: PageProps) {
<>
{
if (lintErrors.length === 0) {
diff --git a/src/components/Seo.tsx b/src/components/Seo.tsx
index 79f19f87c..bb6c50ffd 100644
--- a/src/components/Seo.tsx
+++ b/src/components/Seo.tsx
@@ -9,6 +9,7 @@ import {siteConfig} from '../siteConfig';
export interface SeoProps {
title: string;
+ titleForTitleTag: undefined | string;
description?: string;
image?: string;
// jsonld?: JsonLDType | Array;
@@ -36,7 +37,7 @@ function getDomain(languageCode: string): string {
export const Seo = withRouter(
({
title,
- description = 'The library for web and native user interfaces',
+ titleForTitleTag,
image = '/images/og-default.png',
router,
children,
@@ -47,14 +48,20 @@ export const Seo = withRouter(
const canonicalUrl = `https://${siteDomain}${
router.asPath.split(/[\?\#]/)[0]
}`;
- const pageTitle = isHomePage ? title : title + ' – React';
+ // Allow setting a different title for Google results
+ const pageTitle =
+ (titleForTitleTag ?? title) + (isHomePage ? '' : ' – React');
// Twitter's meta parser is not very good.
const twitterTitle = pageTitle.replace(/[<>]/g, '');
+ let description = isHomePage
+ ? 'React est une bibliothèque pour des interfaces utilisateurs web et natives. Construisez des interfaces utilisateurs à partir de briques individuelles appelées composants, écrites en JavaScript. React est conçu pour vous permettre de combiner sans effort des composants produits par des acteurs distincts, qu’il s’agisse de personnes, d’équipes ou d’organisations entières.'
+ : 'La bibliothèque pour des interfaces utilisateurs web et natives';
return (
{title != null && {pageTitle}}
- {description != null && (
+ {isHomePage && (
+ // Let Google figure out a good description for each page.
)}
diff --git a/src/content/learn/describing-the-ui.md b/src/content/learn/describing-the-ui.md
index fd7635efd..ed9d1a4c7 100644
--- a/src/content/learn/describing-the-ui.md
+++ b/src/content/learn/describing-the-ui.md
@@ -529,13 +529,21 @@ React utilise des arbres pour modéliser les relations entre les composants ou l
Un arbre de rendu React représente les relations parent-enfants entre les composants.
-Un exemple d’arbre de rendu React.
+
+
+Un exemple d’arbre de rendu React.
+
+
Les composants proches du haut de l'arbre, près du composant racine, sont considérés comme des composants de haut niveau. Les composants qui n'ont pas de composants enfants sont qualifiés de composants feuilles. La catégorisation des composants aide à comprendre le flux de données et les performances de rendu.
Une autre manière utile de percevoir votre application consiste à modéliser les relations entre les modules JavaScript. Nous parlons alors d'arbre de dépendances de modules.
-Un exemple d’arbre de dépendances de modules.
+
+
+Un exemple d’arbre de dépendances de modules.
+
+
On utilise souvent un arbre de dépendances dans les outils de *build* pour *bundler* tout le code JavaScript que le client devra télécharger pour assurer le rendu. Un *bundle* massif nuira à l'expérience utilisateur des applis React. Comprendre l'arborescence des dépendances de modules aide à déboguer ces problèmes.
diff --git a/src/content/learn/reacting-to-input-with-state.md b/src/content/learn/reacting-to-input-with-state.md
index b537d41b8..75f71c3a4 100644
--- a/src/content/learn/reacting-to-input-with-state.md
+++ b/src/content/learn/reacting-to-input-with-state.md
@@ -84,7 +84,7 @@ function submitForm(answer) {
// Imaginez que ça fait une requête réseau
return new Promise((resolve, reject) => {
setTimeout(() => {
- if (answer.toLowerCase() == 'istanbul') {
+ if (answer.toLowerCase() === 'istanbul') {
resolve();
} else {
reject(new Error('Bonne idée, mais mauvaise réponse. Réessayez !'));
diff --git a/src/content/learn/understanding-your-ui-as-a-tree.md b/src/content/learn/understanding-your-ui-as-a-tree.md
index 31e11aefb..e3991dd62 100644
--- a/src/content/learn/understanding-your-ui-as-a-tree.md
+++ b/src/content/learn/understanding-your-ui-as-a-tree.md
@@ -252,7 +252,7 @@ Avec le rendu conditionnel, d'un rendu à l'autre, l'arbre de rendu peut différ
Dans cet exemple, selon la valeur de `inspiration.type`, nous pouvons afficher soit `` soit ``. L'arbre de rendu peut être différent d'une passe de rendu à l'autre.
-Même si les arbres de rendu peuvent varier d'un rendu à l'autre, ces arbres restent utiles pour identifier les composants racine et feuilles d'une appli React. Les composants de haut niveau sont ceux les plus proches du composant racine, et peuvent impacter la performance de tous les composants en-dessous d'eux. Ce sont souvent eux qui ont la plus forte complexité. Les composants feuilles sont vers le bas de l'arbre, n'ont pas de composants enfants et refont fréquemment leur rendu.
+Même si les arbres de rendu peuvent varier d'un rendu à l'autre, ces arbres restent utiles pour identifier les composants *racines* et *feuilles* d'une appli React. Les composants de haut niveau sont ceux les plus proches du composant racine, et peuvent impacter la performance de tous les composants en-dessous d'eux. Ce sont souvent eux qui ont la plus forte complexité. Les composants feuilles sont vers le bas de l'arbre, n'ont pas de composants enfants et refont fréquemment leur rendu.
Il est utile de bien identifier ces catégories de composants pour comprendre le flux de données et les performances de votre appli.
diff --git a/src/content/reference/react-dom/components/form.md b/src/content/reference/react-dom/components/form.md
new file mode 100644
index 000000000..7c6023220
--- /dev/null
+++ b/src/content/reference/react-dom/components/form.md
@@ -0,0 +1,435 @@
+---
+title: "
` {/*form*/}
+
+To create interactive controls for submitting information, render the [built-in browser `
` supports all [common element props.](/reference/react-dom/components/common#props)
+
+[`action`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form#action): a URL or function. When a URL is passed to `action` the form will behave like the HTML form component. When a function is passed to `action` the function will handle the form submission. The function passed to `action` may be async and will be called with a single argument containing the [form data](https://developer.mozilla.org/en-US/docs/Web/API/FormData) of the submitted form. The `action` prop can be overridden by a `formAction` attribute on a `
}
+ >
+
+
+ Search
+
+
+ );
+}
+
+```
+
+```json package.json hidden
+{
+ "dependencies": {
+ "react": "18.3.0-canary-6db7f4209-20231021",
+ "react-dom": "18.3.0-canary-6db7f4209-20231021",
+ "react-scripts": "^5.0.0",
+ "react-error-boundary": "4.0.3"
+ },
+ "main": "/index.js",
+ "devDependencies": {}
+}
+```
+
+
+
+### Display a form submission error without JavaScript {/*display-a-form-submission-error-without-javascript*/}
+
+Displaying a form submission error message before the JavaScript bundle loads for progressive enhancement requires that:
+
+1. `
` be rendered by a [Server Component](/reference/react/use-client)
+1. the function passed to the `
`'s `action` prop be a [Server Action](/reference/react/use-server)
+1. the `useFormState` Hook be used to display the error message
+
+`useFormState` takes two parameters: a [Server Action](/reference/react/use-server) and an initial state. `useFormState` returns two values, a state variable and an action. The action returned by `useFormState` should be passed to the `action` prop of the form. The state variable returned by `useFormState` can be used to displayed an error message. The value returned by the [Server Action](/reference/react/use-server) passed to `useFormState` will be used to update the state variable.
+
+
+
+```js App.js
+import { useFormState } from "react-dom";
+import { signUpNewUser } from "./api";
+
+export default function Page() {
+ async function signup(prevState, formData) {
+ "use server";
+ const email = formData.get("email");
+ try {
+ await signUpNewUser(email);
+ alert(`Added "${email}"`);
+ } catch (err) {
+ return err.toString();
+ }
+ }
+ const [message, formAction] = useFormState(signup, null);
+ return (
+ <>
+
Signup for my newsletter
+
Signup with the same email twice to see an error
+
+
+
+ Sign up
+ {!!message &&
{message}
}
+
+ >
+ );
+}
+```
+
+```js api.js hidden
+let emails = [];
+
+export async function signUpNewUser(newEmail) {
+ if (emails.includes(newEmail)) {
+ throw new Error("This email address has already been added");
+ }
+ emails.push(newEmail);
+}
+```
+
+```json package.json hidden
+{
+ "dependencies": {
+ "react": "18.3.0-canary-6db7f4209-20231021",
+ "react-dom": "18.3.0-canary-6db7f4209-20231021",
+ "react-scripts": "^5.0.0"
+ },
+ "main": "/index.js",
+ "devDependencies": {}
+}
+```
+
+
+
+Learn more about updating state from a form action with the [`useFormState`](/reference/react-dom/hooks/useFormState) docs
+
+### Handling multiple submission types {/*handling-multiple-submission-types*/}
+
+Forms can be designed to handle multiple submission actions based on the button pressed by the user. Each button inside a form can be associated with a distinct action or behavior by setting the `formAction` prop.
+
+When a user taps a specific button, the form is submitted, and a corresponding action, defined by that button's attributes and action, is executed. For instance, a form might submit an article for review by default but have a separate button with `formAction` set to save the article as a draft.
+
+
+
+```js App.js
+export default function Search() {
+ function publish(formData) {
+ const content = formData.get("content");
+ const button = formData.get("button");
+ alert(`'${content}' was published with the '${button}' button`);
+ }
+
+ function save(formData) {
+ const content = formData.get("content");
+ alert(`Your draft of '${content}' has been saved!`);
+ }
+
+ return (
+
+
+
+ Publish
+ Save draft
+
+ );
+}
+```
+
+```json package.json hidden
+{
+ "dependencies": {
+ "react": "18.3.0-canary-6db7f4209-20231021",
+ "react-dom": "18.3.0-canary-6db7f4209-20231021",
+ "react-scripts": "^5.0.0"
+ },
+ "main": "/index.js",
+ "devDependencies": {}
+}
+```
+
+
diff --git a/src/content/reference/react-dom/components/input.md b/src/content/reference/react-dom/components/input.md
index 79d6ce26d..d3af0ef13 100644
--- a/src/content/reference/react-dom/components/input.md
+++ b/src/content/reference/react-dom/components/input.md
@@ -32,6 +32,14 @@ Pour afficher un champ de saisie, utilisez le [composant natif `` du navi
`` prend en charge toutes les [props communes aux éléments](/reference/react-dom/components/common#props).
+
+
+Les extensions de React à la prop `formAction` ne sont actuellement disponibles que sur les canaux de livraison Canary et Expérimental de React. Dans les versions stables de React, `formAction` est limitée à son fonctionnement [du composant HTML natif du navigateur](https://react.dev/reference/react-dom/components#all-html-components). Apprenez-en davantage sur [les canaux de livraison React](/community/versioning-policy#all-release-channels).
+
+
+
+[`formAction`](https://developer.mozilla.org/fr/docs/Web/HTML/Element/input#formaction) : une chaîne de caractères ou une fonction. Cette prop a priorité sur le `
` pour les champs de `type="submit"` ou `type="image"`. Lorsqu'une URL est passée à `action`, le formulaire se comporte comme un formulaire HTML classique. Mais si une fonction est passée à `formAction`, la fonction traitera l'envoi du formulaire. Allez voir [`
`](/reference/react-dom/components/form#props).
+
Un champ de saisie peut devenir un [champ contrôlé](#controlling-an-input-with-a-state-variable) en lui passant une de ces props :
* [`checked`](https://developer.mozilla.org/fr/docs/Web/API/HTMLInputElement#checked) : un booléen. Pour un champ de saisie avec une case à cocher ou un bouton radio, contrôle s'il est sélectionné.
diff --git a/src/content/reference/react-dom/hooks/index.md b/src/content/reference/react-dom/hooks/index.md
index 6ad448b86..2c4f28ed6 100644
--- a/src/content/reference/react-dom/hooks/index.md
+++ b/src/content/reference/react-dom/hooks/index.md
@@ -21,7 +21,7 @@ Les Hooks de formulaires ne sont actuellement disponibles que sur les canaux de
Les *formulaires* vous permettent de créer des contrôles interactifs pour envoyer des informations. Pour gérer les formulaires dans vos composants, utilisez l'un des Hooks suivants :
* [`useFormStatus`](/reference/react-dom/hooks/useFormStatus) vous permet de mettre à jour l'UI sur base de l'état d'un formulaire.
-* `useFormState` vous permet de gérer l'état au sein d'un formulaire.
+* [`useFormState`](/reference/react-dom/hooks/useFormState) vous permet de gérer l'état au sein d'un formulaire.
```js
function Form({ action }) {
diff --git a/src/content/reference/react-dom/hooks/useFormState.md b/src/content/reference/react-dom/hooks/useFormState.md
new file mode 100644
index 000000000..53c73ae38
--- /dev/null
+++ b/src/content/reference/react-dom/hooks/useFormState.md
@@ -0,0 +1,291 @@
+---
+title: useFormState
+canary: true
+---
+
+
+
+The `useFormState` Hook is currently only available in React's canary and experimental channels. Learn more about [release channels here](/community/versioning-policy#all-release-channels). In addition, you need to use a framework that supports [React Server Components](/reference/react/use-client) to get the full benefit of `useFormState`.
+
+
+
+
+
+`useFormState` is a Hook that allows you to update state based on the result of a form action.
+
+```js
+const [state, formAction] = useFormState(fn, initialState);
+```
+
+
+
+
+
+---
+
+## Reference {/*reference*/}
+
+### `useFormState(action, initialState)` {/*useformstate*/}
+
+{/* TODO T164397693: link to actions documentation once it exists */}
+
+Call `useFormState` at the top level of your component to create component state that is updated [when a form action is invoked](/reference/react-dom/components/form). You pass `useFormState` an existing form action function as well as an initial state, and it returns a new action that you use in your form, along with the latest form state. The latest form state is also passed to the function that you provided.
+
+```js
+import { useFormState } from "react-dom";
+
+async function increment(previousState, formData) {
+ return previousState + 1;
+}
+
+function StatefulForm({}) {
+ const [state, formAction] = useFormState(increment, 0);
+ return (
+
+ {state}
+ Increment
+
+ )
+}
+```
+
+The form state is the value returned by the action when the form was last submitted. If the form has not yet been submitted, it is the initial state that you pass.
+
+If used with a server action, `useFormState` allows the server's response from submitting the form to be shown even before hydration has completed.
+
+[See more examples below.](#usage)
+
+#### Parameters {/*parameters*/}
+
+* `fn`: The function to be called when the form is submitted or button pressed. When the function is called, it will receive the previous state of the form (initially the `initialState` that you pass, subsequently its previous return value) as its initial argument, followed by the arguments that a form action normally receives.
+* `initialState`: The value you want the state to be initially. It can be any serializable value. This argument is ignored after the action is first invoked.
+
+{/* TODO T164397693: link to serializable values docs once it exists */}
+
+#### Returns {/*returns*/}
+
+`useFormState` returns an array with exactly two values:
+
+1. The current state. During the first render, it will match the `initialState` you have passed. After the action is invoked, it will match the value returned by the action.
+2. A new action that you can pass as the `action` prop to your `form` component or `formAction` prop to any `button` component within the form.
+
+#### Caveats {/*caveats*/}
+
+* When used with a framework that supports React Server Components, `useFormState` lets you make forms interactive before JavaScript has executed on the client. When used without Server Components, it is equivalent to component local state.
+* The function passed to `useFormState` receives an extra argument, the previous or initial state, as its first argument. This makes its signature different than if it were used directly as a form action without using `useFormState`.
+
+---
+
+## Usage {/*usage*/}
+
+### Using information returned by a form action {/*using-information-returned-by-a-form-action*/}
+
+Call `useFormState` at the top level of your component to access the return value of an action from the last time a form was submitted.
+
+```js [[1, 5, "state"], [2, 5, "formAction"], [3, 5, "action"], [4, 5, "null"], [2, 8, "formAction"]]
+import { useFormState } from 'react-dom';
+import { action } from './actions.js';
+
+function MyComponent() {
+ const [state, formAction] = useFormState(action, null);
+ // ...
+ return (
+
+ {/* ... */}
+
+ );
+}
+```
+
+`useFormState` returns an array with exactly two items:
+
+1. The current state of the form, which is initially set to the initial state you provided, and after the form is submitted is set to the return value of the action you provided.
+2. A new action that you pass to `
` as its `action` prop.
+
+When the form is submitted, the action function that you provided will be called. Its return value will become the new current state of the form.
+
+The action that you provide will also receive a new first argument, namely the current state of the form. The first time the form is submitted, this will be the initial state you provided, while with subsequent submissions, it will be the return value from the last time the action was called. The rest of the arguments are the same as if `useFormState` had not been used
+
+```js [[3, 1, "action"], [1, 1, "currentState"]]
+function action(currentState, formData) {
+ // ...
+ return 'next state';
+}
+```
+
+
+
+#### Display form errors {/*display-form-errors*/}
+
+To display messages such as an error message or toast that's returned by a server action, wrap the action in a call to `useFormState`.
+
+
+
+```js App.js
+import { useState } from "react";
+import { useFormState } from "react-dom";
+import { addToCart } from "./actions.js";
+
+function AddToCartForm({itemID, itemTitle}) {
+ const [message, formAction] = useFormState(addToCart, null);
+ return (
+
+
{itemTitle}
+
+ Add to Cart
+ {message}
+
+ );
+}
+
+export default function App() {
+ return (
+ <>
+
+
+ >
+ )
+}
+```
+
+```js actions.js
+"use server";
+
+export async function addToCart(prevState, queryData) {
+ const itemID = queryData.get('itemID');
+ if (itemID === "1") {
+ return "Added to cart";
+ } else {
+ return "Couldn't add to cart: the item is sold out.";
+ }
+}
+```
+
+```css styles.css hidden
+form {
+ border: solid 1px black;
+ margin-bottom: 24px;
+ padding: 12px
+}
+
+form button {
+ margin-right: 12px;
+}
+```
+
+```json package.json hidden
+{
+ "dependencies": {
+ "react": "canary",
+ "react-dom": "canary",
+ "react-scripts": "^5.0.0"
+ },
+ "main": "/index.js",
+ "devDependencies": {}
+}
+```
+
+
+
+
+#### Display structured information after submitting a form {/*display-structured-information-after-submitting-a-form*/}
+
+The return value from a server action can be any serializable value. For example, it could be an object that includes a boolean indicating whether the action was successful, an error message, or updated information.
+
+
+
+```js App.js
+import { useState } from "react";
+import { useFormState } from "react-dom";
+import { addToCart } from "./actions.js";
+
+function AddToCartForm({itemID, itemTitle}) {
+ const [formState, formAction] = useFormState(addToCart, {});
+ return (
+
+
{itemTitle}
+
+ Add to Cart
+ {formState?.success &&
+
+ Added to cart! Your cart now has {formState.cartSize} items.
+
+ }
+ {formState?.success === false &&
+
+ Failed to add to cart: {formState.message}
+
+ }
+
+ );
+}
+
+export default function App() {
+ return (
+ <>
+
+
+ >
+ )
+}
+```
+
+```js actions.js
+"use server";
+
+export async function addToCart(prevState, queryData) {
+ const itemID = queryData.get('itemID');
+ if (itemID === "1") {
+ return {
+ success: true,
+ cartSize: 12,
+ };
+ } else {
+ return {
+ success: false,
+ message: "The item is sold out.",
+ };
+ }
+}
+```
+
+```css styles.css hidden
+form {
+ border: solid 1px black;
+ margin-bottom: 24px;
+ padding: 12px
+}
+
+form button {
+ margin-right: 12px;
+}
+```
+
+```json package.json hidden
+{
+ "dependencies": {
+ "react": "canary",
+ "react-dom": "canary",
+ "react-scripts": "^5.0.0"
+ },
+ "main": "/index.js",
+ "devDependencies": {}
+}
+```
+
+
+
+
+
+
+## Troubleshooting {/*troubleshooting*/}
+
+### My action can no longer read the submitted form data {/*my-action-can-no-longer-read-the-submitted-form-data*/}
+
+When you wrap an action with `useFormState`, it gets an extra argument *as its first argument*. The submitted form data is therefore its *second* argument instead of its first as it would usually be. The new first argument that gets added is the current state of the form.
+
+```js
+function action(currentState, formData) {
+ // ...
+}
+```
diff --git a/src/content/reference/react-dom/server/renderToPipeableStream.md b/src/content/reference/react-dom/server/renderToPipeableStream.md
index fb15f3823..eae704bc0 100644
--- a/src/content/reference/react-dom/server/renderToPipeableStream.md
+++ b/src/content/reference/react-dom/server/renderToPipeableStream.md
@@ -433,7 +433,7 @@ function ProfilePage() {
}
```
-Si une erreur survient au sein du composant `Posts` ou d'un de ses enfants, React [tentera automatiquement de retomber sur ses pieds](/reference/react/Suspense#providing-a-fallback-for-server-errors-and-server-only-content) :
+Si une erreur survient au sein du composant `Posts` ou d'un de ses enfants, React [tentera automatiquement de retomber sur ses pieds](/reference/react/Suspense#providing-a-fallback-for-server-errors-and-client-only-content) :
1. Il émettra le contenu de secours du périmètre `` le plus proche (`PostsGlimmer`) dans le HTML.
2. Il « laissera tomber » le rendu côté serveur du contenu de `Posts`.
diff --git a/src/content/reference/react-dom/server/renderToReadableStream.md b/src/content/reference/react-dom/server/renderToReadableStream.md
index a2e555f3d..6bbe40e49 100644
--- a/src/content/reference/react-dom/server/renderToReadableStream.md
+++ b/src/content/reference/react-dom/server/renderToReadableStream.md
@@ -438,7 +438,7 @@ function ProfilePage() {
}
```
-Si une erreur survient au sein du composant `Posts` ou d'un de ses enfants, React [tentera automatiquement de retomber sur ses pieds](/reference/react/Suspense#providing-a-fallback-for-server-errors-and-server-only-content) :
+Si une erreur survient au sein du composant `Posts` ou d'un de ses enfants, React [tentera automatiquement de retomber sur ses pieds](/reference/react/Suspense#providing-a-fallback-for-server-errors-and-client-only-content) :
1. Il émettra le contenu de secours du périmètre `` le plus proche (`PostsGlimmer`) dans le HTML.
2. Il « laissera tomber » le rendu côté serveur du contenu de `Posts`.
diff --git a/src/content/reference/react/experimental_taintUniqueValue.md b/src/content/reference/react/experimental_taintUniqueValue.md
index 1d25d11dd..4946956e2 100644
--- a/src/content/reference/react/experimental_taintUniqueValue.md
+++ b/src/content/reference/react/experimental_taintUniqueValue.md
@@ -67,6 +67,7 @@ experimental_taintUniqueValue(
#### Limitations {/*caveats*/}
- La dérivation de valeurs à partir des valeurs ternies peut nuire à la protection par ternissement. Les nouvelles valeurs créées par exemple en changeant la casse de valeurs ternies, en concaténant des chaînes ternies vers une chaîne de caractères plus longue, en convertissant des valeurs ternies en Base 64, en extrayant des portions de chaînes ternies, ou toute autre transformation du même genre, ne constituent plus des valeurs ternies à moins que vous n'appeliez explicitement `taintUniqueValue` sur les nouvelles valeurs ainsi produites.
+- N'utilisez pas `taintUniqueValue` pour protéger des valeurs à basse entropie, telles que des codes PIN ou des numéros de téléphones. Si une valeur de requête est contrôlée par vos attaquants, ils peuvent alors déterminer la valeur ternie en énumérant toutes les valeurs possibles du secret.
---
diff --git a/src/content/reference/react/use-client.md b/src/content/reference/react/use-client.md
index b4edfc976..778bbad54 100644
--- a/src/content/reference/react/use-client.md
+++ b/src/content/reference/react/use-client.md
@@ -1,5 +1,6 @@
---
title: "'use client'"
+titleForTitleTag: "Directive 'use client'"
canary: true
---
diff --git a/src/content/reference/react/use-server.md b/src/content/reference/react/use-server.md
index d0981752c..8d18fca78 100644
--- a/src/content/reference/react/use-server.md
+++ b/src/content/reference/react/use-server.md
@@ -1,5 +1,6 @@
---
title: "'use server'"
+titleForTitleTag: "Directive 'use server'"
canary: true
---
diff --git a/src/content/reference/react/useLayoutEffect.md b/src/content/reference/react/useLayoutEffect.md
index 5fed052dd..c18990964 100644
--- a/src/content/reference/react/useLayoutEffect.md
+++ b/src/content/reference/react/useLayoutEffect.md
@@ -734,7 +734,7 @@ Quoi qu'il en soit, si vous rencontrez ce problème, vous avez quelques options
- Remplacez `useLayoutEffec` par [`useEffect`](/reference/react/useEffect). Ça dit à React qu'il peut afficher le rendu initial sans bloquer le rafraîchissement (puisque le HTML d'origine deviendra visible avant que votre Effet ne soit exécuté).
-- Vous pouvez aussi [indiquer que votre composant est réservé au côté client](/reference/react/Suspense#providing-a-fallback-for-server-errors-and-server-only-content). Ça indique à React qu'il faudra en remplacer le contenu jusqu'au périmètre [``](/reference/react/Suspense) le plus proche par un contenu de secours (par exemple un *spinner* ou un squelette structurel) pendant le rendu côté serveur.
+- Vous pouvez aussi [indiquer que votre composant est réservé au côté client](/reference/react/Suspense#providing-a-fallback-for-server-errors-and-client-only-content). Ça indique à React qu'il faudra en remplacer le contenu jusqu'au périmètre [``](/reference/react/Suspense) le plus proche par un contenu de secours (par exemple un *spinner* ou un squelette structurel) pendant le rendu côté serveur.
- Vous pouvez encore ne faire le rendu d'un composant qui recourt à `useLayoutEffect` qu'après l'hydratation. Maintenez un état booléen `isMounted` initialisé à `false`, que vous mettrez à `true` au sein d'un appel à `useEffect`. Votre logique de rendu peut alors ressembler à `return isMounted ? : `. Côté serveur et pendant l'hydratation, l'utilisateur verra le `FallbackContent` qui, lui, n'appellera pas `useLayoutEffect`. Puis React le remplacera par `RealContent` qui s'exécute côté client uniquement et pourra inclure des appels à `useLayoutEffect`.
diff --git a/src/content/reference/react/useOptimistic.md b/src/content/reference/react/useOptimistic.md
new file mode 100644
index 000000000..d0511b1a9
--- /dev/null
+++ b/src/content/reference/react/useOptimistic.md
@@ -0,0 +1,145 @@
+---
+title: useOptimistic
+canary: true
+---
+
+
+
+The `useOptimistic` Hook is currently only available in React's canary and experimental channels. Learn more about [React's release channels here](/community/versioning-policy#all-release-channels).
+
+
+
+
+
+`useOptimistic` is a React Hook that lets you optimistically update the UI.
+
+```js
+ const [optimisticState, addOptimistic] = useOptimistic(state, updateFn);
+```
+
+
+
+
+
+---
+
+## Reference {/*reference*/}
+
+### `useOptimistic(state, updateFn)` {/*use*/}
+
+`useOptimistic` is a React hook that lets you show a different state while an async action is underway. It accepts some state as an argument and returns a copy of that state that can be different during the duration of an async action such as a network request. You provide a function that takes the current state and the input to the action, and returns the optimistic state to be used while the action is pending.
+
+This state is called the "optimistic" state because it is usually used to immediately present the user with the result of performing an action, even though the action actually takes time to complete.
+
+```js
+import { useOptimistic } from 'react';
+
+function AppContainer() {
+ const [optimisticState, addOptimistic] = useOptimistic(
+ state,
+ // updateFn
+ (currentState, optimisticValue) => {
+ // merge and return new state
+ // with optimistic value
+ }
+ );
+}
+```
+
+[See more examples below.](#usage)
+
+#### Parameters {/*parameters*/}
+
+* `state`: the value to be returned initially and whenever no action is pending.
+* `updateFn(currentState, optimisticValue)`: a function that takes the current state and the optimistic value passed to `addOptimistic` and returns the resulting optimistic state. It must be a pure function. `updateFn` takes in two parameters. The `currentState` and the `optimisticValue`. The return value will be the merged value of the `currentState` and `optimisticValue`.
+
+
+#### Returns {/*returns*/}
+
+* `optimisticState`: The resulting optimistic state. It is equal to `state` unless an action is pending, in which case it is equal to the value returned by `updateFn`.
+* `addOptimistic`: `addOptimistic` is the dispatching function to call when you have an optimistic update. It takes one argument, `optimisticValue`, of any type and will call the `updateFn` with `state` and `optimisticValue`.
+
+---
+
+## Usage {/*usage*/}
+
+### Optimistically updating forms {/*optimistically-updating-with-forms*/}
+
+The `useOptimistic` Hook provides a way to optimistically update the user interface before a background operation, like a network request, completes. In the context of forms, this technique helps to make apps feel more responsive. When a user submits a form, instead of waiting for the server's response to reflect the changes, the interface is immediately updated with the expected outcome.
+
+For example, when a user types a message into the form and hits the "Send" button, the `useOptimistic` Hook allows the message to immediately appear in the list with a "Sending..." label, even before the message is actually sent to a server. This "optimistic" approach gives the impression of speed and responsiveness. The form then attempts to truly send the message in the background. Once the server confirms the message has been received, the "Sending..." label is removed.
+
+
+
+
+```js App.js
+import { useOptimistic, useState, useRef } from "react";
+import { deliverMessage } from "./actions.js";
+
+function Thread({ messages, sendMessage }) {
+ const formRef = useRef();
+ async function formAction(formData) {
+ addOptimisticMessage(formData.get("message"));
+ formRef.current.reset();
+ await sendMessage(formData);
+ }
+ const [optimisticMessages, addOptimisticMessage] = useOptimistic(
+ messages,
+ (state, newMessage) => [
+ ...state,
+ {
+ text: newMessage,
+ sending: true
+ }
+ ]
+ );
+
+ return (
+ <>
+ {optimisticMessages.map((message, index) => (
+