diff --git a/apps/docs/content/fr/docs/01-app/01-getting-started/01-installation.mdx b/apps/docs/content/fr/docs/01-app/01-getting-started/01-installation.mdx new file mode 100644 index 00000000..861fae96 --- /dev/null +++ b/apps/docs/content/fr/docs/01-app/01-getting-started/01-installation.mdx @@ -0,0 +1,341 @@ +--- +source-updated-at: 2025-06-01T01:32:20.000Z +translation-updated-at: 2025-06-02T20:03:23.405Z +title: Comment configurer un nouveau projet Next.js +nav_title: Installation +description: Créez une nouvelle application Next.js avec l'interface CLI `create-next-app`, et configurez TypeScript, ESLint et les alias de module. +--- + +{/* Le contenu de ce document est partagé entre le routeur App et Pages. Vous pouvez utiliser le composant `Contenu` pour ajouter du contenu spécifique au routeur Pages. Tout contenu partagé ne doit pas être encapsulé dans un composant. */} + +## Configuration système requise + +Avant de commencer, assurez-vous que votre système répond aux exigences suivantes : + +- [Node.js 18.18](https://nodejs.org/) ou version ultérieure. +- macOS, Windows (y compris WSL), ou Linux. + +## Installation automatique + +Le moyen le plus rapide de créer une nouvelle application Next.js est d'utiliser [`create-next-app`](/docs/app/api-reference/cli/create-next-app), qui configure tout automatiquement pour vous. Pour créer un projet, exécutez : + +```bash filename="Terminal" +npx create-next-app@latest +``` + +Lors de l'installation, vous verrez les invites suivantes : + +```txt filename="Terminal" +Quel est le nom de votre projet ? my-app +Souhaitez-vous utiliser TypeScript ? Non / Oui +Souhaitez-vous utiliser ESLint ? Non / Oui +Souhaitez-vous utiliser Tailwind CSS ? Non / Oui +Souhaitez-vous placer votre code dans un répertoire `src/` ? Non / Oui +Souhaitez-vous utiliser le routeur App ? (recommandé) Non / Oui +Souhaitez-vous utiliser Turbopack pour `next dev` ? Non / Oui +Souhaitez-vous personnaliser l'alias d'importation (`@/*` par défaut) ? Non / Oui +Quel alias d'importation souhaitez-vous configurer ? @/* +``` + +Après les invites, [`create-next-app`](/docs/app/api-reference/cli/create-next-app) créera un dossier avec le nom de votre projet et installera les dépendances nécessaires. + +## Installation manuelle + +Pour créer manuellement une nouvelle application Next.js, installez les paquets requis : + +```bash filename="Terminal" +npm install next@latest react@latest react-dom@latest +``` + +Ensuite, ajoutez les scripts suivants à votre fichier `package.json` : + +```json filename="package.json" +{ + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint" + } +} +``` + +Ces scripts correspondent aux différentes étapes du développement d'une application : + +- `next dev` : Démarre le serveur de développement. +- `next build` : Construit l'application pour la production. +- `next start` : Démarre le serveur de production. +- `next lint` : Exécute ESLint. + + + +### Créer le répertoire `app` + +Next.js utilise le routage par système de fichiers, ce qui signifie que les routes de votre application sont déterminées par la structure de vos fichiers. + +Créez un dossier `app`. Ensuite, à l'intérieur de `app`, créez un fichier `layout.tsx`. Ce fichier est le [layout racine](/docs/app/api-reference/file-conventions/layout#root-layout). Il est obligatoire et doit contenir les balises `` et ``. + +```tsx filename="app/layout.tsx" switcher +export default function RootLayout({ + children, +}: { + children: React.ReactNode +}) { + return ( + + {children} + + ) +} +``` + +```jsx filename="app/layout.js" switcher +export default function RootLayout({ children }) { + return ( + + {children} + + ) +} +``` + +Créez une page d'accueil `app/page.tsx` avec un contenu initial : + +```tsx filename="app/page.tsx" switcher +export default function Page() { + return

Bonjour, Next.js !

+} +``` + +```jsx filename="app/page.js" switcher +export default function Page() { + return

Bonjour, Next.js !

+} +``` + +Les fichiers `layout.tsx` et `page.tsx` seront rendus lorsque l'utilisateur visitera la racine de votre application (`/`). + +Structure du dossier App + +> **Bon à savoir** : +> +> - Si vous oubliez de créer le layout racine, Next.js créera automatiquement ce fichier lors de l'exécution du serveur de développement avec `next dev`. +> - Vous pouvez optionnellement utiliser un [dossier `src`](/docs/app/api-reference/file-conventions/src-folder) à la racine de votre projet pour séparer le code de votre application des fichiers de configuration. + +
+ + + +### Créer le répertoire `pages` + +Next.js utilise le routage par système de fichiers, ce qui signifie que les routes de votre application sont déterminées par la structure de vos fichiers. + +Créez un répertoire `pages` à la racine de votre projet. Ensuite, ajoutez un fichier `index.tsx` dans votre dossier `pages`. Ce sera votre page d'accueil (`/`) : + +```tsx filename="pages/index.tsx" switcher +export default function Page() { + return

Bonjour, Next.js !

+} +``` + +```jsx filename="pages/index.js" switcher +export default function Page() { + return

Bonjour, Next.js !

+} +``` + +Ensuite, ajoutez un fichier `_app.tsx` dans `pages/` pour définir le layout global. En savoir plus sur le [fichier App personnalisé](/docs/pages/building-your-application/routing/custom-app). + +```tsx filename="pages/_app.tsx" switcher +import type { AppProps } from 'next/app' + +export default function App({ Component, pageProps }: AppProps) { + return +} +``` + +```jsx filename="pages/_app.js" switcher +export default function App({ Component, pageProps }) { + return +} +``` + +Enfin, ajoutez un fichier `_document.tsx` dans `pages/` pour contrôler la réponse initiale du serveur. En savoir plus sur le [fichier Document personnalisé](/docs/pages/building-your-application/routing/custom-document). + +```tsx filename="pages/_document.tsx" switcher +import { Html, Head, Main, NextScript } from 'next/document' + +export default function Document() { + return ( + + + +
+ + + + ) +} +``` + +```jsx filename="pages/_document.js" switcher +import { Html, Head, Main, NextScript } from 'next/document' + +export default function Document() { + return ( + + + +
+ + + + ) +} +``` + + + +### Créer le dossier `public` (optionnel) + +Créez un [dossier `public`](/docs/app/api-reference/file-conventions/public-folder) à la racine de votre projet pour stocker les ressources statiques telles que les images, polices, etc. Les fichiers à l'intérieur de `public` peuvent ensuite être référencés par votre code à partir de l'URL de base (`/`). + +Vous pouvez ensuite référencer ces ressources en utilisant le chemin racine (`/`). Par exemple, `public/profile.png` peut être référencé comme `/profile.png` : + +```tsx filename="app/page.tsx" highlight={4} switcher +import Image from 'next/image' + +export default function Page() { + return Profil +} +``` + +```jsx filename="app/page.js" highlight={4} switcher +import Image from 'next/image' + +export default function Page() { + return Profil +} +``` + +## Exécuter le serveur de développement + +1. Exécutez `npm run dev` pour démarrer le serveur de développement. +2. Visitez `http://localhost:3000` pour voir votre application. +3. Modifiez le fichier `app/page.tsx``pages/index.tsx` et enregistrez-le pour voir le résultat mis à jour dans votre navigateur. + +## Configurer TypeScript + +> Version minimale de TypeScript : `v4.5.2` + +Next.js inclut un support intégré de TypeScript. Pour ajouter TypeScript à votre projet, renommez un fichier en `.ts` / `.tsx` et exécutez `next dev`. Next.js installera automatiquement les dépendances nécessaires et ajoutera un fichier `tsconfig.json` avec les options de configuration recommandées. + + + +### Plugin IDE + +Next.js inclut un plugin TypeScript personnalisé et un vérificateur de types, que VSCode et d'autres éditeurs de code peuvent utiliser pour une vérification de types avancée et une auto-complétion. + +Vous pouvez activer le plugin dans VS Code en : + +1. Ouvrant la palette de commandes (`Ctrl/⌘` + `Shift` + `P`) +2. Recherchant "TypeScript : Sélectionner la version de TypeScript" +3. Sélectionnant "Utiliser la version de l'espace de travail" + +Palette de commandes TypeScript + + + +Consultez la page [Référence TypeScript](/docs/app/api-reference/config/next-config-js/typescript) pour plus d'informations. + +## Configurer ESLint + +Next.js inclut ESLint intégré. Il installe automatiquement les paquets nécessaires et configure les paramètres appropriés lorsque vous créez un nouveau projet avec `create-next-app`. + +Pour ajouter manuellement ESLint à un projet existant, ajoutez `next lint` comme script à `package.json` : + +```json filename="package.json" +{ + "scripts": { + "lint": "next lint" + } +} +``` + +Ensuite, exécutez `npm run lint` et vous serez guidé à travers le processus d'installation et de configuration. + +```bash filename="Terminal" +npm run lint +``` + +Vous verrez une invite comme celle-ci : + +> ? Comment souhaitez-vous configurer ESLint ? +> +> ❯ Strict (recommandé) +> Base +> Annuler + +- **Strict** : Inclut la configuration de base ESLint de Next.js ainsi qu'un ensemble de règles plus strictes pour les Core Web Vitals. C'est la configuration recommandée pour les développeurs configurant ESLint pour la première fois. +- **Base** : Inclut la configuration de base ESLint de Next.js. +- **Annuler** : Ignorer la configuration. Choisissez cette option si vous prévoyez de configurer votre propre configuration ESLint personnalisée. + +Si `Strict` ou `Base` sont sélectionnés, Next.js installera automatiquement `eslint` et `eslint-config-next` comme dépendances dans votre application et créera un fichier `.eslintrc.json` à la racine de votre projet qui inclut votre configuration sélectionnée. + +Vous pouvez maintenant exécuter `next lint` chaque fois que vous souhaitez exécuter ESLint pour détecter les erreurs. Une fois ESLint configuré, il s'exécutera également automatiquement lors de chaque construction (`next build`). Les erreurs feront échouer la construction, tandis que les avertissements ne le feront pas. + +Consultez la page [Plugin ESLint](/docs/app/api-reference/config/next-config-js/eslint) pour plus d'informations. + +## Configurer les imports absolus et les alias de module + +Next.js prend en charge nativement les options `"paths"` et `"baseUrl"` des fichiers `tsconfig.json` et `jsconfig.json`. + +Ces options vous permettent d'aliasser les répertoires du projet vers des chemins absolus, rendant l'importation de modules plus facile et plus propre. Par exemple : + +```jsx +// Avant +import { Button } from '../../../components/button' + +// Après +import { Button } from '@/components/button' +``` + +Pour configurer les imports absolus, ajoutez l'option `baseUrl` à votre fichier `tsconfig.json` ou `jsconfig.json`. Par exemple : + +```json filename="tsconfig.json ou jsconfig.json" +{ + "compilerOptions": { + "baseUrl": "src/" + } +} +``` + +En plus de configurer le chemin `baseUrl`, vous pouvez utiliser l'option `"paths"` pour `"aliasser"` les chemins de module. + +Par exemple, la configuration suivante mappe `@/components/*` vers `components/*` : + +```json filename="tsconfig.json ou jsconfig.json" +{ + "compilerOptions": { + "baseUrl": "src/", + "paths": { + "@/styles/*": ["styles/*"], + "@/components/*": ["components/*"] + } + } +} +``` + +Chacun des `"paths"` est relatif à l'emplacement `baseUrl`. \ No newline at end of file diff --git a/apps/docs/content/fr/docs/01-app/01-getting-started/02-project-structure.mdx b/apps/docs/content/fr/docs/01-app/01-getting-started/02-project-structure.mdx new file mode 100644 index 00000000..e8085f04 --- /dev/null +++ b/apps/docs/content/fr/docs/01-app/01-getting-started/02-project-structure.mdx @@ -0,0 +1,408 @@ +--- +source-updated-at: 2025-06-01T01:32:20.000Z +translation-updated-at: 2025-06-02T20:05:04.517Z +title: Structure et organisation du projet +nav_title: Structure du projet +description: Un aperçu des conventions de dossiers et fichiers dans Next.js, et comment organiser votre projet. +--- + +Cette page fournit un aperçu de **toutes** les conventions de dossiers et fichiers dans Next.js, ainsi que des recommandations pour organiser votre projet. + +## Conventions de dossiers et fichiers + +### Dossiers de premier niveau + +Les dossiers de premier niveau sont utilisés pour organiser le code et les ressources statiques de votre application. + +Segments de route en segments de chemin + +| | | +| ------------------------------------------------------------------ | ---------------------------------- | +| [`app`](/docs/app/building-your-application/routing) | Routeur d'application | +| [`pages`](/docs/pages/building-your-application/routing) | Routeur de pages | +| [`public`](/docs/app/api-reference/file-conventions/public-folder) | Ressources statiques à servir | +| [`src`](/docs/app/api-reference/file-conventions/src-folder) | Dossier source optionnel de l'application | + +### Fichiers de premier niveau + +Les fichiers de premier niveau sont utilisés pour configurer votre application, gérer les dépendances, exécuter des middlewares, intégrer des outils de surveillance et définir des variables d'environnement. + +| | | +| ---------------------------------------------------------------------------- | --------------------------------------- | +| **Next.js** | | +| [`next.config.js`](/docs/app/api-reference/config/next-config-js) | Fichier de configuration pour Next.js | +| [`package.json`](/docs/app/getting-started/installation#manual-installation) | Dépendances et scripts du projet | +| [`instrumentation.ts`](/docs/app/guides/instrumentation) | Fichier OpenTelemetry et Instrumentation | +| [`middleware.ts`](/docs/app/building-your-application/routing/middleware) | Middleware de requête Next.js | +| [`.env`](/docs/app/guides/environment-variables) | Variables d'environnement | +| [`.env.local`](/docs/app/guides/environment-variables) | Variables d'environnement locales | +| [`.env.production`](/docs/app/guides/environment-variables) | Variables d'environnement de production | +| [`.env.development`](/docs/app/guides/environment-variables) | Variables d'environnement de développement | +| [`.eslintrc.json`](/docs/app/api-reference/config/eslint) | Fichier de configuration pour ESLint | +| `.gitignore` | Fichiers et dossiers à ignorer pour Git | +| `next-env.d.ts` | Fichier de déclaration TypeScript pour Next.js | +| `tsconfig.json` | Fichier de configuration pour TypeScript | +| `jsconfig.json` | Fichier de configuration pour JavaScript | + + + +### Fichiers de routage + +| | | | +| ----------------------------------------------------------------------------- | ------------------- | ---------------------------- | +| [`layout`](/docs/app/api-reference/file-conventions/layout) | `.js` `.jsx` `.tsx` | Mise en page | +| [`page`](/docs/app/api-reference/file-conventions/page) | `.js` `.jsx` `.tsx` | Page | +| [`loading`](/docs/app/api-reference/file-conventions/loading) | `.js` `.jsx` `.tsx` | UI de chargement | +| [`not-found`](/docs/app/api-reference/file-conventions/not-found) | `.js` `.jsx` `.tsx` | UI de page non trouvée | +| [`error`](/docs/app/api-reference/file-conventions/error) | `.js` `.jsx` `.tsx` | UI d'erreur | +| [`global-error`](/docs/app/api-reference/file-conventions/error#global-error) | `.js` `.jsx` `.tsx` | UI d'erreur globale | +| [`route`](/docs/app/api-reference/file-conventions/route) | `.js` `.ts` | Point de terminaison API | +| [`template`](/docs/app/api-reference/file-conventions/template) | `.js` `.jsx` `.tsx` | Mise en page re-rendue | +| [`default`](/docs/app/api-reference/file-conventions/default) | `.js` `.jsx` `.tsx` | Page de repli pour les routes parallèles | + +### Routes imbriquées + +| | | +| --------------- | -------------------- | +| `dossier` | Segment de route | +| `dossier/dossier` | Segment de route imbriqué | + +### Routes dynamiques + +| | | +| ------------------------------------------------------------------------------------------------------ | -------------------------------- | +| [`[dossier]`](/docs/app/api-reference/file-conventions/dynamic-routes#convention) | Segment de route dynamique | +| [`[...dossier]`](/docs/app/api-reference/file-conventions/dynamic-routes#catch-all-segments) | Segment de route attrape-tout | +| [`[[...dossier]]`](/docs/app/api-reference/file-conventions/dynamic-routes#optional-catch-all-segments) | Segment de route attrape-tout optionnel | + +### Groupes de routes et dossiers privés + +| | | +| ------------------------------------------------------------------------------ | ------------------------------------------------ | +| [`(dossier)`](/docs/app/api-reference/file-conventions/route-groups#convention) | Grouper des routes sans affecter le routage | +| [`_dossier`](#private-folders) | Exclure un dossier et ses segments enfants du routage | + +### Routes parallèles et interceptées + +| | | +| ------------------------------------------------------------------------------------------- | -------------------------- | +| [`@dossier`](/docs/app/api-reference/file-conventions/parallel-routes#slots) | Emplacement nommé | +| [`(.)dossier`](/docs/app/api-reference/file-conventions/intercepting-routes#convention) | Interception au même niveau | +| [`(..)dossier`](/docs/app/api-reference/file-conventions/intercepting-routes#convention) | Interception un niveau au-dessus | +| [`(..)(..)dossier`](/docs/app/api-reference/file-conventions/intercepting-routes#convention) | Interception deux niveaux au-dessus | +| [`(...)dossier`](/docs/app/api-reference/file-conventions/intercepting-routes#convention) | Interception depuis la racine | + +### Conventions de fichiers de métadonnées + +#### Icônes d'application + +| | | | +| --------------------------------------------------------------------------------------------------------------- | ----------------------------------- | ------------------------ | +| [`favicon`](/docs/app/api-reference/file-conventions/metadata/app-icons#favicon) | `.ico` | Fichier favicon | +| [`icon`](/docs/app/api-reference/file-conventions/metadata/app-icons#icon) | `.ico` `.jpg` `.jpeg` `.png` `.svg` | Fichier d'icône d'application | +| [`icon`](/docs/app/api-reference/file-conventions/metadata/app-icons#generate-icons-using-code-js-ts-tsx) | `.js` `.ts` `.tsx` | Icône d'application générée | +| [`apple-icon`](/docs/app/api-reference/file-conventions/metadata/app-icons#apple-icon) | `.jpg` `.jpeg`, `.png` | Fichier d'icône Apple | +| [`apple-icon`](/docs/app/api-reference/file-conventions/metadata/app-icons#generate-icons-using-code-js-ts-tsx) | `.js` `.ts` `.tsx` | Icône Apple générée | + +#### Images Open Graph et Twitter + +| | | | +| --------------------------------------------------------------------------------------------------------------------------- | ---------------------------- | -------------------------- | +| [`opengraph-image`](/docs/app/api-reference/file-conventions/metadata/opengraph-image#opengraph-image) | `.jpg` `.jpeg` `.png` `.gif` | Fichier image Open Graph | +| [`opengraph-image`](/docs/app/api-reference/file-conventions/metadata/opengraph-image#generate-images-using-code-js-ts-tsx) | `.js` `.ts` `.tsx` | Image Open Graph générée | +| [`twitter-image`](/docs/app/api-reference/file-conventions/metadata/opengraph-image#twitter-image) | `.jpg` `.jpeg` `.png` `.gif` | Fichier image Twitter | +| [`twitter-image`](/docs/app/api-reference/file-conventions/metadata/opengraph-image#generate-images-using-code-js-ts-tsx) | `.js` `.ts` `.tsx` | Image Twitter générée | + +#### SEO + +| | | | +| ------------------------------------------------------------------------------------------------------------ | ----------- | --------------------- | +| [`sitemap`](/docs/app/api-reference/file-conventions/metadata/sitemap#sitemap-files-xml) | `.xml` | Fichier sitemap | +| [`sitemap`](/docs/app/api-reference/file-conventions/metadata/sitemap#generating-a-sitemap-using-code-js-ts) | `.js` `.ts` | Sitemap généré | +| [`robots`](/docs/app/api-reference/file-conventions/metadata/robots#static-robotstxt) | `.txt` | Fichier robots | +| [`robots`](/docs/app/api-reference/file-conventions/metadata/robots#generate-a-robots-file) | `.js` `.ts` | Fichier robots généré | + + + + + +### Conventions de fichiers + +| | | | +| ----------------------------------------------------------------------------------------------------------- | ------------------- | ----------------- | +| [`_app`](/docs/pages/building-your-application/routing/custom-app) | `.js` `.jsx` `.tsx` | App personnalisée | +| [`_document`](/docs/pages/building-your-application/routing/custom-document) | `.js` `.jsx` `.tsx` | Document personnalisé | +| [`_error`](/docs/pages/building-your-application/routing/custom-error#more-advanced-error-page-customizing) | `.js` `.jsx` `.tsx` | Page d'erreur personnalisée | +| [`404`](/docs/pages/building-your-application/routing/custom-error#404-page) | `.js` `.jsx` `.tsx` | Page d'erreur 404 | +| [`500`](/docs/pages/building-your-application/routing/custom-error#500-page) | `.js` `.jsx` `.tsx` | Page d'erreur 500 | + +### Routes + +| | | | +| ---------------------------------------------------------------------------------------------- | ------------------- | ----------- | +| **Convention de dossier** | | | +| [`index`](/docs/pages/building-your-application/routing/pages-and-layouts#index-routes) | `.js` `.jsx` `.tsx` | Page d'accueil | +| [`dossier/index`](/docs/pages/building-your-application/routing/pages-and-layouts#index-routes) | `.js` `.jsx` `.tsx` | Page imbriquée | +| **Convention de fichier** | | | +| [`index`](/docs/pages/building-your-application/routing/pages-and-layouts#index-routes) | `.js` `.jsx` `.tsx` | Page d'accueil | +| [`fichier`](/docs/pages/building-your-application/routing/pages-and-layouts) | `.js` `.jsx` `.tsx` | Page imbriquée | + +### Routes dynamiques + +| | | | +| ----------------------------------------------------------------------------------------------------------------- | ------------------- | -------------------------------- | +| **Convention de dossier** | | | +| [`[dossier]/index`](/docs/pages/building-your-application/routing/dynamic-routes) | `.js` `.jsx` `.tsx` | Segment de route dynamique | +| [`[...dossier]/index`](/docs/pages/building-your-application/routing/dynamic-routes#catch-all-segments) | `.js` `.jsx` `.tsx` | Segment de route attrape-tout | +| [`[[...dossier]]/index`](/docs/pages/building-your-application/routing/dynamic-routes#optional-catch-all-segments) | `.js` `.jsx` `.tsx` | Segment de route attrape-tout optionnel | +| **Convention de fichier** | | | +| [`[fichier]`](/docs/pages/building-your-application/routing/dynamic-routes) | `.js` `.jsx` `.tsx` | Segment de route dynamique | +| [`[...fichier]`](/docs/pages/building-your-application/routing/dynamic-routes#catch-all-segments) | `.js` `.jsx` `.tsx` | Segment de route attrape-tout | +| [`[[...fichier]]`](/docs/pages/building-your-application/routing/dynamic-routes#optional-catch-all-segments) | `.js` `.jsx` `.tsx` | Segment de route attrape-tout optionnel | + + + + + +## Organisation de votre projet + +Next.js est **non-opinionated** sur la façon dont vous organisez et colocalisez les fichiers de votre projet. Mais il fournit plusieurs fonctionnalités pour vous aider à organiser votre projet. + +### Hiérarchie des composants + +Les composants définis dans les fichiers spéciaux sont rendus dans une hiérarchie spécifique : + +- `layout.js` +- `template.js` +- `error.js` (limite d'erreur React) +- `loading.js` (limite de suspense React) +- `not-found.js` (limite d'erreur React) +- `page.js` ou `layout.js` imbriqué + +Hiérarchie des composants pour les conventions de fichiers + +Les composants sont rendus de manière récursive dans les routes imbriquées, ce qui signifie que les composants d'un segment de route seront imbriqués **à l'intérieur** des composants de son segment parent. + +Hiérarchie des composants imbriqués pour les conventions de fichiers + + + +### Colocalisation + +Dans le répertoire `app`, les dossiers imbriqués définissent la structure des routes. Chaque dossier représente un segment de route qui est mappé à un segment correspondant dans un chemin d'URL. + +Cependant, même si la structure des routes est définie par des dossiers, une route **n'est pas accessible publiquement** tant qu'un fichier `page.js` ou `route.js` n'est pas ajouté à un segment de route. + +Un diagramme montrant comment une route n'est pas accessible publiquement tant qu'un fichier page.js ou route.js n'est pas ajouté à un segment de route. + +Et, même lorsqu'une route est rendue accessible publiquement, seul le **conenu renvoyé** par `page.js` ou `route.js` est envoyé au client. + +Un diagramme montrant comment les fichiers page.js et route.js rendent les routes accessibles publiquement. + +Cela signifie que les **fichiers du projet** peuvent être **sécurisés par colocalisation** à l'intérieur des segments de route dans le répertoire `app` sans risquer d'être accessibles par erreur. + +Un diagramme montrant que les fichiers colocalisés du projet ne sont pas accessibles même lorsqu'un segment contient un fichier page.js ou route.js. + +> **Bon à savoir** : Bien que vous **puissiez** colocaliser vos fichiers de projet dans `app`, vous n'êtes **pas obligé**. Si vous préférez, vous pouvez [les conserver en dehors du répertoire `app`](#store-project-files-outside-of-app). + +### Dossiers privés + +Les dossiers privés peuvent être créés en préfixant un dossier avec un tiret bas : `_nomDuDossier` + +Cela indique que le dossier est un détail d'implémentation privé et ne doit pas être pris en compte par le système de routage, **excluant ainsi le dossier et tous ses sous-dossiers** du routage. + +Un exemple de structure de dossier utilisant des dossiers privés + +Comme les fichiers dans le répertoire `app` peuvent être [sécurisés par colocalisation par défaut](#colocation), les dossiers privés ne sont pas nécessaires pour la colocalisation. Cependant, ils peuvent être utiles pour : + +- Séparer la logique d'interface utilisateur de la logique de routage. +- Organiser de manière cohérente les fichiers internes dans un projet et l'écosystème Next.js. +- Trier et regrouper les fichiers dans les éditeurs de code. +- Éviter les conflits de noms potentiels avec les futures conventions de fichiers Next.js. + +> **Bon à savoir** : +> +> - Bien que ce ne soit pas une convention du framework, vous pourriez également envisager de marquer les fichiers en dehors des dossiers privés comme "privés" en utilisant le même motif de tiret bas. +> - Vous pouvez créer des segments d'URL commençant par un tiret bas en préfixant le nom du dossier avec `%5F` (la forme encodée d'un tiret bas) : `%5FnomDuDossier`. +> - Si vous n'utilisez pas de dossiers privés, il serait utile de connaître les [conventions de fichiers spéciales](/docs/app/getting-started/project-structure#routing-files) de Next.js pour éviter des conflits de noms inattendus. + +### Groupes de routes + +Les groupes de routes peuvent être créés en entourant un dossier de parenthèses : `(nomDuDossier)` + +Cela indique que le dossier est à des fins d'organisation et **ne doit pas être inclus** dans le chemin d'URL de la route. + +Un exemple de structure de dossier utilisant des groupes de routes + +Les groupes de routes sont utiles pour : + +- Organiser les routes par section du site, intention ou équipe. Par exemple, pages marketing, pages admin, etc. +- Permettre des mises en page imbriquées au même niveau de segment de route : + - [Créer plusieurs mises en page imbriquées dans le même segment, y compris plusieurs mises en page racine](#creating-multiple-root-layouts) + - [Ajouter une mise en page à un sous-ensemble de routes dans un segment commun](#opting-specific-segments-into-a-layout) + +### Dossier `src` + +Next.js prend en charge le stockage du code de l'application (y compris `app`) dans un dossier [`src` optionnel](/docs/app/api-reference/file-conventions/src-folder). Cela sépare le code de l'application des fichiers de configuration du projet qui se trouvent principalement à la racine d'un projet. + +Un exemple de structure de dossier avec le dossier `src` + +## Exemples + +La section suivante présente une vue d'ensemble très générale des stratégies courantes. Le principal conseil est de choisir une stratégie qui fonctionne pour vous et votre équipe et de rester cohérent dans tout le projet. + +> **Bon à savoir** : Dans nos exemples ci-dessous, nous utilisons les dossiers `components` et `lib` comme placeholders génériques, leur nom n'a pas de signification particulière dans le framework et vos projets pourraient utiliser d'autres dossiers comme `ui`, `utils`, `hooks`, `styles`, etc. + +### Stocker les fichiers de projet en dehors de `app` + +Cette stratégie stocke tout le code de l'application dans des dossiers partagés à la **racine de votre projet** et conserve le répertoire `app` uniquement pour les besoins de routage. + +Un exemple de structure de dossier avec les fichiers de projet en dehors de app + +### Stocker les fichiers de projet dans des dossiers de niveau supérieur à l'intérieur de `app` + +Cette stratégie stocke tout le code de l'application dans des dossiers partagés à la **racine du répertoire `app`**. + +Un exemple de structure de dossier avec les fichiers de projet à l'intérieur de app + +### Diviser les fichiers de projet par fonctionnalité ou route + +Cette stratégie stocke le code partagé globalement dans le répertoire racine `app` et **divise** le code plus spécifique dans les segments de route qui l'utilisent. + +Un exemple de structure de dossier avec les fichiers de projet divisés par fonctionnalité ou route + +### Organiser les routes sans affecter le chemin d'URL + +Pour organiser les routes sans affecter l'URL, créez un groupe pour garder les routes liées ensemble. Les dossiers entre parenthèses seront omis de l'URL (par exemple `(marketing)` ou `(shop)`). + +Organiser les routes avec des groupes de routes + +Même si les routes à l'intérieur de `(marketing)` et `(shop)` partagent la même hiérarchie d'URL, vous pouvez créer une mise en page différente pour chaque groupe en ajoutant un fichier `layout.js` dans leurs dossiers. + +Groupes de routes avec plusieurs mises en page + +### Opter pour une mise en page sur des segments spécifiques + +Pour opter pour une mise en page sur des routes spécifiques, créez un nouveau groupe de routes (par exemple `(shop)`) et déplacez les routes qui partagent la même mise en page dans le groupe (par exemple `account` et `cart`). Les routes en dehors du groupe ne partageront pas la mise en page (par exemple `checkout`). + +Groupes de routes avec mises en page opt-in + +### Opter pour des squelettes de chargement sur une route spécifique + +Pour appliquer un [squelette de chargement](/docs/app/building-your-application/routing/loading-ui-and-streaming) via un fichier `loading.js` à une route spécifique, créez un nouveau groupe de routes (par exemple `/(overview)`) puis placez votre `loading.tsx` à l'intérieur de ce groupe de routes. + +Structure de dossier montrant un loading.tsx et un page.tsx à l'intérieur du groupe de routes + +Maintenant, le fichier `loading.tsx` ne s'appliquera qu'à votre page dashboard → overview au lieu de toutes vos pages dashboard sans affecter la structure du chemin d'URL. + +### Créer plusieurs mises en page racine + +Pour créer plusieurs [mises en page racine](/docs/app/api-reference/file-conventions/layout#root-layout), supprimez le fichier `layout.js` de niveau supérieur et ajoutez un fichier `layout.js` dans chaque groupe de routes. Cela est utile pour partitionner une application en sections ayant une interface ou une expérience complètement différente. Les balises `` et `` doivent être ajoutées à chaque mise en page racine. + +Groupes de routes avec plusieurs mises en page racine + +Dans l'exemple ci-dessus, `(marketing)` et `(shop)` ont chacun leur propre mise en page racine. + + diff --git a/apps/docs/content/fr/docs/01-app/01-getting-started/03-layouts-and-pages.mdx b/apps/docs/content/fr/docs/01-app/01-getting-started/03-layouts-and-pages.mdx new file mode 100644 index 00000000..3c4849a0 --- /dev/null +++ b/apps/docs/content/fr/docs/01-app/01-getting-started/03-layouts-and-pages.mdx @@ -0,0 +1,294 @@ +--- +source-updated-at: 2025-06-01T01:32:20.000Z +translation-updated-at: 2025-06-02T20:02:44.649Z +title: Comment créer des layouts et des pages +nav_title: Layouts et Pages +description: Créez vos premières pages et layouts, et établissez des liens entre elles. +related: + title: Référence API + description: Apprenez-en plus sur les fonctionnalités mentionnées dans cette page en consultant la Référence API. + links: + - app/api-reference/file-conventions/layout + - app/api-reference/file-conventions/page + - app/api-reference/components/link + - app/api-reference/file-conventions/dynamic-routes +--- + +Next.js utilise un **routage basé sur le système de fichiers**, ce qui signifie que vous pouvez utiliser des dossiers et des fichiers pour définir des routes. Cette page vous guidera pour créer des layouts et des pages, et établir des liens entre elles. + +## Créer une page + +Une **page** est une interface utilisateur rendue sur une route spécifique. Pour créer une page, ajoutez un fichier [`page`](/docs/app/api-reference/file-conventions/page) dans le dossier `app` et exportez par défaut un composant React. Par exemple, pour créer une page d'accueil (`/`) : + +Fichier spécial page.js + +```tsx filename="app/page.tsx" switcher +export default function Page() { + return

Hello Next.js!

+} +``` + +```jsx filename="app/page.js" switcher +export default function Page() { + return

Hello Next.js!

+} +``` + +## Créer un layout + +Un layout est une interface utilisateur **partagée** entre plusieurs pages. Lors de la navigation, les layouts préservent l'état, restent interactifs et ne sont pas re-rendus. + +Vous pouvez définir un layout en exportant par défaut un composant React depuis un fichier [`layout`](/docs/app/api-reference/file-conventions/layout). Le composant doit accepter une prop `children` qui peut être une page ou un autre [layout](#imbriquer-des-layouts). + +Par exemple, pour créer un layout qui accepte votre page d'accueil comme enfant, ajoutez un fichier `layout` dans le dossier `app` : + +Fichier spécial layout.js + +```tsx filename="app/layout.tsx" switcher +export default function DashboardLayout({ + children, +}: { + children: React.ReactNode +}) { + return ( + + + {/* UI du layout */} + {/* Placez children là où vous voulez rendre une page ou un layout imbriqué */} +
{children}
+ + + ) +} +``` + +```jsx filename="app/layout.js" switcher +export default function DashboardLayout({ children }) { + return ( + + + {/* UI du layout */} + {/* Placez children là où vous voulez rendre une page ou un layout imbriqué */} +
{children}
+ + + ) +} +``` + +Le layout ci-dessus est appelé [root layout](/docs/app/api-reference/file-conventions/layout#root-layout) car il est défini à la racine du dossier `app`. Le root layout est **obligatoire** et doit contenir les balises `html` et `body`. + +## Créer une route imbriquée + +Une route imbriquée est une route composée de plusieurs segments d'URL. Par exemple, la route `/blog/[slug]` est composée de trois segments : + +- `/` (Segment racine) +- `blog` (Segment) +- `[slug]` (Segment feuille) + +Dans Next.js : + +- Les **dossiers** sont utilisés pour définir les segments de route qui correspondent aux segments d'URL. +- Les **fichiers** (comme `page` et `layout`) sont utilisés pour créer l'interface utilisateur affichée pour un segment. + +Pour créer des routes imbriquées, vous pouvez imbriquer des dossiers les uns dans les autres. Par exemple, pour ajouter une route pour `/blog`, créez un dossier appelé `blog` dans le dossier `app`. Ensuite, pour rendre `/blog` accessible publiquement, ajoutez un fichier `page.tsx` : + +Hiérarchie de fichiers montrant un dossier blog et un fichier page.js + +```tsx filename="app/blog/page.tsx" switcher +// Imports fictifs +import { getPosts } from '@/lib/posts' +import { Post } from '@/ui/post' + +export default async function Page() { + const posts = await getPosts() + + return ( +
    + {posts.map((post) => ( + + ))} +
+ ) +} +``` + +```jsx filename="app/blog/[slug]/page.js" switcher +// Imports fictifs +import { getPosts } from '@/lib/posts' +import { Post } from '@/ui/post' + +export default async function Page() { + const posts = await getPosts() + + return ( +
    + {posts.map((post) => ( + + ))} +
+ ) +} +``` + +Vous pouvez continuer à imbriquer des dossiers pour créer des routes imbriquées. Par exemple, pour créer une route pour un article de blog spécifique, créez un nouveau dossier `[slug]` dans `blog` et ajoutez un fichier `page` : + +Hiérarchie de fichiers montrant un dossier blog avec un dossier slug imbriqué et un fichier page.js + +```tsx filename="app/blog/[slug]/page.tsx" switcher +function generateStaticParams() {} + +export default function Page() { + return

Hello, Blog Post Page!

+} +``` + +```jsx filename="app/blog/[slug]/page.js" switcher +function generateStaticParams() {} + +export default function Page() { + return

Hello, Blog Post Page!

+} +``` + +Envelopper un nom de dossier entre crochets (par exemple `[slug]`) crée un [segment de route dynamique](/docs/app/api-reference/file-conventions/dynamic-routes) qui est utilisé pour générer plusieurs pages à partir de données, comme des articles de blog, des pages produits, etc. + +## Imbriquer des layouts + +Par défaut, les layouts dans la hiérarchie de dossiers sont également imbriqués, ce qui signifie qu'ils englobent les layouts enfants via leur prop `children`. Vous pouvez imbriquer des layouts en ajoutant `layout` dans des segments de route spécifiques (dossiers). + +Par exemple, pour créer un layout pour la route `/blog`, ajoutez un nouveau fichier `layout` dans le dossier `blog`. + +Hiérarchie de fichiers montrant le root layout englobant le layout blog + +```tsx filename="app/blog/layout.tsx" switcher +export default function BlogLayout({ + children, +}: { + children: React.ReactNode +}) { + return
{children}
+} +``` + +```jsx filename="app/blog/layout.js" switcher +export default function BlogLayout({ children }) { + return
{children}
+} +``` + +Si vous combinez les deux layouts ci-dessus, le root layout (`app/layout.js`) engloberait le layout blog (`app/blog/layout.js`), qui engloberait à son tour la page blog (`app/blog/page.js`) et la page d'article de blog (`app/blog/[slug]/page.js`). + +## Créer un segment dynamique + +Les [segments dynamiques](/docs/app/api-reference/file-conventions/dynamic-routes) vous permettent de créer des routes générées à partir de données. Par exemple, au lieu de créer manuellement une route pour chaque article de blog individuel, vous pouvez créer un segment dynamique pour générer les routes en fonction des données des articles de blog. + +Pour créer un segment dynamique, enveloppez le nom du segment (dossier) entre crochets : `[segmentName]`. Par exemple, dans la route `app/blog/[slug]/page.tsx`, `[slug]` est le segment dynamique. + +```tsx filename="app/blog/[slug]/page.tsx" switcher +export default async function BlogPostPage({ + params, +}: { + params: Promise<{ slug: string }> +}) { + const { slug } = await params + const post = await getPost(slug) + + return ( +
+

{post.title}

+

{post.content}

+
+ ) +} +``` + +```jsx filename="app/blog/[slug]/page.js" switcher +export default async function BlogPostPage({ params }) { + const { slug } = await params + const post = await getPost(slug) + + return ( +
+

{post.title}

+

{post.content}

+
+ ) +} +``` + +Apprenez-en plus sur les [segments dynamiques](/docs/app/api-reference/file-conventions/dynamic-routes). + +## Établir des liens entre les pages + +Vous pouvez utiliser le [composant ``](/docs/app/api-reference/components/link) pour naviguer entre les routes. `` est un composant intégré de Next.js qui étend la balise HTML `` pour fournir le [préchargement](/docs/app/building-your-application/routing/linking-and-navigating#2-prefetching) et la [navigation côté client](/docs/app/building-your-application/routing/linking-and-navigating#5-soft-navigation). + +Par exemple, pour générer une liste d'articles de blog, importez `` depuis `next/link` et passez une prop `href` au composant : + +```tsx filename="app/ui/post.tsx" highlight={1,10} switcher +import Link from 'next/link' + +export default async function Post({ post }) { + const posts = await getPosts() + + return ( +
    + {posts.map((post) => ( +
  • + {post.title} +
  • + ))} +
+ ) +} +``` + +```jsx filename="app/ui/post.js" highlight={1,10} switcher +import Link from 'next/link' + +export default async function Post({ post }) { + const posts = await getPosts() + + return ( +
    + {posts.map((post) => ( +
  • + {post.title} +
  • + ))} +
+ ) +} +``` + +`` est la méthode principale et recommandée pour naviguer entre les routes dans votre application Next.js. Cependant, vous pouvez également utiliser le [hook `useRouter`](/docs/app/api-reference/functions/use-router) pour une navigation plus avancée. \ No newline at end of file diff --git a/apps/docs/content/fr/docs/01-app/01-getting-started/04-images.mdx b/apps/docs/content/fr/docs/01-app/01-getting-started/04-images.mdx new file mode 100644 index 00000000..85936c1a --- /dev/null +++ b/apps/docs/content/fr/docs/01-app/01-getting-started/04-images.mdx @@ -0,0 +1,199 @@ +--- +source-updated-at: 2025-06-02T15:30:01.000Z +translation-updated-at: 2025-06-02T20:02:08.743Z +title: Comment optimiser les images +nav_title: Images +description: Apprenez comment optimiser les images dans Next.js +related: + title: Référence API + description: Consultez la référence API pour l'ensemble complet des fonctionnalités de l'image Next.js. + links: + - app/api-reference/components/image +--- + +Le composant [``](/docs/app/api-reference/components/image) de Next.js étend l'élément HTML `` pour fournir : + +- **Optimisation de taille :** Servir automatiquement des images de la bonne taille pour chaque appareil, en utilisant des formats modernes comme WebP. +- **Stabilité visuelle :** Empêcher automatiquement le [décalage de mise en page (layout shift)](https://web.dev/articles/cls) lors du chargement des images. +- **Chargement plus rapide des pages :** Ne charger les images que lorsqu'elles entrent dans la zone visible grâce au chargement différé natif du navigateur, avec des placeholders de flou optionnels. +- **Flexibilité des assets :** Redimensionner les images à la demande, même celles stockées sur des serveurs distants. + +Pour commencer à utiliser ``, importez-le depuis `next/image` et utilisez-le dans votre composant. + +```tsx filename="app/page.tsx" switcher +import Image from 'next/image' + +export default function Page() { + return +} +``` + +```jsx filename="app/page.js" switcher +import Image from 'next/image' + +export default function Page() { + return +} +``` + +La propriété `src` peut être une image [locale](#local-images) ou [distante](#remote-images). + +> **🎥 Regardez :** En savoir plus sur l'utilisation de `next/image` → [YouTube (9 minutes)](https://youtu.be/IU_qq_c_lKA). + +## Images locales + +Vous pouvez stocker des fichiers statiques, comme des images et des polices, dans un dossier appelé [`public`](/docs/app/api-reference/file-conventions/public-folder) à la racine du projet. Les fichiers dans `public` peuvent ensuite être référencés dans votre code à partir de l'URL de base (`/`). + +Structure de dossier montrant les dossiers app et public + +```tsx filename="app/page.tsx" switcher +import Image from 'next/image' + +export default function Page() { + return ( + Photo de l'auteur + ) +} +``` + +```jsx filename="app/page.js" switcher +import Image from 'next/image' + +export default function Page() { + return ( + Photo de l'auteur + ) +} +``` + +### Images importées statiquement + +Vous pouvez aussi importer et utiliser des fichiers image locaux. Next.js déterminera automatiquement la [`width`](/docs/app/api-reference/components/image#width-and-height) et la [`height`](/docs/app/api-reference/components/image#width-and-height) intrinsèques de votre image en fonction du fichier importé. Ces valeurs sont utilisées pour déterminer le ratio de l'image et éviter un [décalage de mise en page cumulatif (Cumulative Layout Shift)](https://web.dev/articles/cls) pendant le chargement de votre image. + +```tsx filename="app/page.tsx" switcher +import Image from 'next/image' +import ProfileImage from './profile.png' + +export default function Page() { + return ( + Photo de l'auteur + ) +} +``` + +```jsx filename="app/page.js" switcher +import Image from 'next/image' +import ProfileImage from './profile.png' + +export default function Page() { + return ( + Photo de l'auteur + ) +} +``` + +Dans ce cas, Next.js s'attend à ce que le fichier `app/profile.png` soit disponible. + +## Images distantes + +Pour utiliser une image distante, vous pouvez fournir une URL sous forme de chaîne pour la propriété `src`. + +```tsx filename="app/page.tsx" switcher +import Image from 'next/image' + +export default function Page() { + return ( + Photo de l'auteur + ) +} +``` + +```jsx filename="app/page.js" switcher +import Image from 'next/image' + +export default function Page() { + return ( + Photo de l'auteur + ) +} +``` + +Comme Next.js n'a pas accès aux fichiers distants pendant la phase de build, vous devez fournir manuellement les propriétés [`width`](/docs/app/api-reference/components/image#width-and-height), [`height`](/docs/app/api-reference/components/image#width-and-height) et optionnellement [`blurDataURL`](/docs/app/api-reference/components/image#blurdataurl). `width` et `height` sont utilisés pour déduire le bon ratio d'aspect de l'image et éviter un décalage de mise en page lors du chargement. + +Pour autoriser en toute sécurité les images provenant de serveurs distants, vous devez définir une liste de modèles d'URL pris en charge dans [`next.config.js`](/docs/app/api-reference/config/next-config-js). Soyez aussi spécifique que possible pour éviter les utilisations malveillantes. Par exemple, la configuration suivante n'autorise que les images provenant d'un bucket AWS S3 spécifique : + +```ts filename="next.config.ts" switcher +import type { NextConfig } from 'next' + +const config: NextConfig = { + images: { + remotePatterns: [ + { + protocol: 'https', + hostname: 's3.amazonaws.com', + port: '', + pathname: '/my-bucket/**', + search: '', + }, + ], + }, +} + +export default config +``` + +```js filename="next.config.js" switcher +module.exports = { + images: { + remotePatterns: [ + { + protocol: 'https', + hostname: 's3.amazonaws.com', + port: '', + pathname: '/my-bucket/**', + search: '', + }, + ], + }, +} +``` \ No newline at end of file diff --git a/apps/docs/content/fr/docs/01-app/01-getting-started/06-css.mdx b/apps/docs/content/fr/docs/01-app/01-getting-started/06-css.mdx new file mode 100644 index 00000000..13d9b3be --- /dev/null +++ b/apps/docs/content/fr/docs/01-app/01-getting-started/06-css.mdx @@ -0,0 +1,295 @@ +--- +source-updated-at: 2025-05-25T15:16:02.000Z +translation-updated-at: 2025-06-02T20:02:19.654Z +title: Comment utiliser CSS dans votre application +nav_title: CSS +description: Découvrez les différentes méthodes pour ajouter CSS à votre application, y compris les modules CSS, le CSS global, Tailwind CSS et plus encore. +related: + title: Étapes suivantes + description: Apprenez-en plus sur les différentes alternatives pour utiliser CSS dans votre application. + links: + - app/guides/tailwind-css + - app/guides/sass + - app/guides/css-in-js +--- + +Next.js offre plusieurs façons d'utiliser CSS dans votre application, notamment : + +- [Modules CSS](#css-modules) +- [CSS global](#css-global) +- [Feuilles de style externes](#feuilles-de-style-externes) +- [Tailwind CSS](/docs/app/guides/tailwind-css) +- [Sass](/docs/app/guides/sass) +- [CSS-in-JS](/docs/app/guides/css-in-js) + +## Modules CSS + +Les modules CSS limitent la portée du CSS en générant des noms de classe uniques. Cela vous permet d'utiliser la même classe dans différents fichiers sans craindre les collisions de noms. + + + +Pour commencer à utiliser les modules CSS, créez un nouveau fichier avec l'extension `.module.css` et importez-le dans n'importe quel composant du répertoire `app` : + +```css filename="app/blog/blog.module.css" +.blog { + padding: 24px; +} +``` + +```tsx filename="app/blog/page.tsx" switcher +import styles from './blog.module.css' + +export default function Page() { + return
+} +``` + +```jsx filename="app/blog/page.js" switcher +import styles from './blog.module.css' + +export default function Layout() { + return
+} +``` + +
+ + + +Pour commencer à utiliser les modules CSS, créez un nouveau fichier avec l'extension `.module.css` et importez-le dans n'importe quel composant du répertoire `pages` : + +```css filename="/styles/blog.module.css" +.blog { + padding: 24px; +} +``` + +```tsx filename="pages/blog/index.tsx" switcher +import styles from './blog.module.css' + +export default function Page() { + return
+} +``` + +```jsx filename="pages/blog/index.js" switcher +import styles from './blog.module.css' + +export default function Page() { + return
+} +``` + +
+ +## CSS global + +Vous pouvez utiliser le CSS global pour appliquer des styles à toute votre application. + + + +Créez un fichier `app/global.css` et importez-le dans la mise en page racine pour appliquer les styles à **chaque route** de votre application : + +```css filename="app/global.css" +body { + padding: 20px 20px 60px; + max-width: 680px; + margin: 0 auto; +} +``` + +```tsx filename="app/layout.tsx" switcher +// Ces styles s'appliquent à chaque route de l'application +import './global.css' + +export default function RootLayout({ + children, +}: { + children: React.ReactNode +}) { + return ( + + {children} + + ) +} +``` + +```jsx filename="app/layout.js" switcher +// Ces styles s'appliquent à chaque route de l'application +import './global.css' + +export default function RootLayout({ children }) { + return ( + + {children} + + ) +} +``` + +> **Bon à savoir :** Les styles globaux peuvent être importés dans n'importe quelle mise en page, page ou composant du répertoire `app`. Cependant, comme Next.js utilise la prise en charge native des feuilles de style par React pour s'intégrer à Suspense, cela ne supprime actuellement pas les feuilles de style lors de la navigation entre les routes, ce qui peut entraîner des conflits. Nous recommandons d'utiliser les styles globaux pour le CSS *vraiment* global, et les [modules CSS](#css-modules) pour le CSS à portée limitée. + + + + + +Importez la feuille de style dans le fichier `pages/_app.js` pour appliquer les styles à **chaque route** de votre application : + +```tsx filename="pages/_app.js" +import '@/styles/global.css' + +export default function MyApp({ Component, pageProps }) { + return +} +``` + +En raison de la nature globale des feuilles de style, et pour éviter les conflits, vous devez les importer dans [`pages/_app.js`](/docs/pages/building-your-application/routing/custom-app). + + + +## Feuilles de style externes + + + +Les feuilles de style publiées par des packages externes peuvent être importées n'importe où dans le répertoire `app`, y compris dans les composants colocalisés : + +```tsx filename="app/layout.tsx" switcher +import 'bootstrap/dist/css/bootstrap.css' + +export default function RootLayout({ + children, +}: { + children: React.ReactNode +}) { + return ( + + {children} + + ) +} +``` + +```jsx filename="app/layout.js" switcher +import 'bootstrap/dist/css/bootstrap.css' + +export default function RootLayout({ children }) { + return ( + + {children} + + ) +} +``` + +> **Bon à savoir :** Dans React 19, `` peut également être utilisé. Consultez la [documentation React sur `link`](https://react.dev/reference/react-dom/components/link) pour plus d'informations. + + + + + +Next.js vous permet d'importer des fichiers CSS depuis un fichier JavaScript. +Ceci est possible car Next.js étend le concept d'[`import`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/import) au-delà de JavaScript. + +### Importer des styles depuis `node_modules` + +Depuis Next.js **9.5.4**, l'importation d'un fichier CSS depuis `node_modules` est autorisée n'importe où dans votre application. + +Pour les feuilles de style globales, comme `bootstrap` ou `nprogress`, vous devez importer le fichier dans `pages/_app.js`. Par exemple : + +```jsx filename="pages/_app.js" +import 'bootstrap/dist/css/bootstrap.css' + +export default function MyApp({ Component, pageProps }) { + return +} +``` + +Pour importer le CSS requis par un composant tiers, vous pouvez le faire dans votre composant. Par exemple : + +```jsx filename="components/example-dialog.js" +import { useState } from 'react' +import { Dialog } from '@reach/dialog' +import VisuallyHidden from '@reach/visually-hidden' +import '@reach/dialog/styles.css' + +function ExampleDialog(props) { + const [showDialog, setShowDialog] = useState(false) + const open = () => setShowDialog(true) + const close = () => setShowDialog(false) + + return ( +
+ + + +

Bonjour. Je suis un dialogue

+
+
+ ) +} +``` + +
+ +## Ordre et fusion + +Next.js optimise le CSS lors des builds de production en regroupant automatiquement (fusionnant) les feuilles de style. **L'ordre de votre CSS** dépend de **l'ordre dans lequel vous importez les styles dans votre code**. + +Par exemple, `base-button.module.css` sera ordonné avant `page.module.css` car `` est importé avant `page.module.css` : + +```tsx filename="page.ts" switcher +import { BaseButton } from './base-button' +import styles from './page.module.css' + +export default function Page() { + return +} +``` + +```jsx filename="page.js" switcher +import { BaseButton } from './base-button' +import styles from './page.module.css' + +export default function Page() { + return +} +``` + +```tsx filename="base-button.tsx" switcher +import styles from './base-button.module.css' + +export function BaseButton() { + return + + ) +} +``` + +```jsx filename="app/ui/counter.tsx" highlight={1} switcher +'use client' + +import { useState } from 'react' + +export default function Counter() { + const [count, setCount] = useState(0) + + return ( +
+

{count} likes

+ +
+ ) +} +``` + +`"use client"` est utilisé pour déclarer une **frontière** entre les graphes (arbres) de modules Serveur et Client. + +Une fois qu'un fichier est marqué avec `"use client"`, **tous ses imports et composants enfants sont considérés comme faisant partie du bundle client**. Cela signifie que vous n'avez pas besoin d'ajouter la directive à chaque composant destiné au client. + +### Réduction de la taille du bundle JS + +Pour réduire la taille de vos bundles JavaScript côté client, ajoutez `'use client'` à des composants interactifs spécifiques au lieu de marquer de grandes parties de votre interface comme composants Client. + +Par exemple, le composant `` contient principalement des éléments statiques comme un logo et des liens de navigation, mais inclut une barre de recherche interactive. `` est interactive et doit être un composant Client, cependant, le reste du layout peut rester un composant Serveur. + +```tsx filename="app/ui/search.tsx" highlight={1} switcher +'use client' + +export default function Search() { + // ... +} +``` + +```jsx filename="app/ui/search.js" highlight={1} switcher +'use client' + +export default function Search() { + // ... +} +``` + +```tsx filename="app/layout.tsx" switcher +// Composant Client +import Search from './search' +// Composant Serveur +import Logo from './logo' + +// Layout est un composant Serveur par défaut +export default function Layout({ children }: { children: React.ReactNode }) { + return ( + <> + +
{children}
+ + ) +} +``` + +```jsx filename="app/layout.js" switcher +// Composant Client +import Search from './search' +// Composant Serveur +import Logo from './logo' + +// Layout est un composant Serveur par défaut +export default function Layout({ children }) { + return ( + <> + +
{children}
+ + ) +} +``` + +### Passage de données des composants Serveur aux composants Client + +Vous pouvez passer des données des composants Serveur aux composants Client en utilisant des props. + +```tsx filename="app/[id]/page.tsx" highlight={1,7} switcher +import LikeButton from '@/app/ui/like-button' +import { getPost } from '@/lib/data' + +export default async function Page({ params }: { params: { id: string } }) { + const post = await getPost(params.id) + + return +} +``` + +```jsx filename="app/[id]/page.js" highlight={1,7} switcher +import LikeButton from '@/app/ui/like-button' +import { getPost } from '@/lib/data' + +export default async function Page({ params }) { + const post = await getPost(params.id) + + return +} +``` + +```tsx filename="app/ui/like-button.tsx" highlight={1} switcher +'use client' + +export default function LikeButton({ likes }: { likes: number }) { + // ... +} +``` + +```jsx filename="app/ui/like-button.js" highlight={1} switcher +'use client' + +export default function LikeButton({ likes }) { + // ... +} +``` + +Alternativement, vous pouvez diffuser (stream) des données d'un composant Serveur vers un composant Client avec le [Hook `use`](https://react.dev/reference/react/use). Voir un [exemple](/docs/app/getting-started/fetching-data#streaming-data-with-the-use-hook). + +> **Bon à savoir** : Les props passées aux composants Client doivent être [sérialisables](https://react.dev/reference/react/use-server#serializable-parameters-and-return-values) par React. + +### Entrelacement des composants Serveur et Client + +Vous pouvez passer des composants Serveur comme prop à un composant Client. Cela vous permet d'imbriquer visuellement une interface rendue côté serveur dans des composants Client. + +Un motif courant consiste à utiliser `children` pour créer un _slot_ dans un ``. Par exemple, un composant `` qui récupère des données côté serveur, à l'intérieur d'un composant `` qui utilise un état client pour basculer la visibilité. + +```tsx filename="app/ui/modal.tsx" switcher +'use client' + +export default function Modal({ children }: { children: React.ReactNode }) { + return
{children}
+} +``` + +```jsx filename="app/ui/modal.js" switcher +'use client' + +export default function Modal({ children }) { + return
{children}
+} +``` + +Ensuite, dans un composant Serveur parent (par exemple ``), vous pouvez passer un `` comme enfant du `` : + +```tsx filename="app/page.tsx" highlight={7} switcher +import Modal from './ui/modal' +import Cart from './ui/cart' + +export default function Page() { + return ( + + + + ) +} +``` + +```jsx filename="app/page.js" highlight={7} switcher +import Modal from './ui/modal' +import Cart from './ui/cart' + +export default function Page() { + return ( + + + + ) +} +``` + +Dans ce motif, tous les composants Serveur seront rendus côté serveur à l'avance, y compris ceux passés comme props. Le RSC Payload résultant contiendra des références indiquant où les composants Client doivent être rendus dans l'arbre des composants. + +### Fournisseurs de contexte (Context providers) + +Le [contexte React](https://react.dev/learn/passing-data-deeply-with-context) est couramment utilisé pour partager un état global comme le thème actuel. Cependant, le contexte React n'est pas pris en charge dans les composants Serveur. + +Pour utiliser un contexte, créez un composant Client qui accepte `children` : + +```tsx filename="app/theme-provider.tsx" switcher +'use client' + +import { createContext } from 'react' + +export const ThemeContext = createContext({}) + +export default function ThemeProvider({ + children, +}: { + children: React.ReactNode +}) { + return {children} +} +``` + +```jsx filename="app/theme-provider.js" switcher +'use client' + +import { createContext } from 'react' + +export const ThemeContext = createContext({}) + +export default function ThemeProvider({ children }) { + return {children} +} +``` + +Ensuite, importez-le dans un composant Serveur (par exemple `layout`) : + +```tsx filename="app/layout.tsx" switcher +import ThemeProvider from './theme-provider' + +export default function RootLayout({ + children, +}: { + children: React.ReactNode +}) { + return ( + + + {children} + + + ) +} +``` + +```jsx filename="app/layout.js" switcher +import ThemeProvider from './theme-provider' + +export default function RootLayout({ children }) { + return ( + + + {children} + + + ) +} +``` + +Votre composant Serveur pourra maintenant rendre directement votre fournisseur, et tous les autres composants Client dans votre application pourront consommer ce contexte. + +> **Bon à savoir** : Vous devriez rendre les fournisseurs aussi profondément que possible dans l'arbre – notez comment `ThemeProvider` n'englobe que `{children}` au lieu de tout le document ``. Cela facilite l'optimisation par Next.js des parties statiques de vos composants Serveur. + +### Composants tiers + +Lorsque vous utilisez un composant tiers qui dépend de fonctionnalités réservées au client, vous pouvez l'encapsuler dans un composant Client pour vous assurer qu'il fonctionne comme prévu. + +Par exemple, le composant `` peut être importé depuis le package `acme-carousel`. Ce composant utilise `useState`, mais il n'a pas encore la directive `"use client"`. + +Si vous utilisez `` dans un composant Client, il fonctionnera comme prévu : + +```tsx filename="app/gallery.tsx" switcher +'use client' + +import { useState } from 'react' +import { Carousel } from 'acme-carousel' + +export default function Gallery() { + const [isOpen, setIsOpen] = useState(false) + + return ( +
+ + {/* Fonctionne, car Carousel est utilisé dans un composant Client */} + {isOpen && } +
+ ) +} +``` + +```jsx filename="app/gallery.js" switcher +'use client' + +import { useState } from 'react' +import { Carousel } from 'acme-carousel' + +export default function Gallery() { + const [isOpen, setIsOpen] = useState(false) + + return ( +
+ + {/* Fonctionne, car Carousel est utilisé dans un composant Client */} + {isOpen && } +
+ ) +} +``` + +Cependant, si vous essayez de l'utiliser directement dans un composant Serveur, vous verrez une erreur. C'est parce que Next.js ne sait pas que `` utilise des fonctionnalités réservées au client. + +Pour résoudre ce problème, vous pouvez encapsuler les composants tiers qui dépendent de fonctionnalités réservées au client dans vos propres composants Client : + +```tsx filename="app/carousel.tsx" switcher +'use client' + +import { Carousel } from 'acme-carousel' + +export default Carousel +``` + +```jsx filename="app/carousel.js" switcher +'use client' + +import { Carousel } from 'acme-carousel' + +export default Carousel +``` + +Maintenant, vous pouvez utiliser `` directement dans un composant Serveur : + +```tsx filename="app/page.tsx" switcher +import Carousel from './carousel' + +export default function Page() { + return ( +
+

View pictures

+ {/* Fonctionne, car Carousel est un composant Client */} + +
+ ) +} +``` + +```jsx filename="app/page.js" switcher +import Carousel from './carousel' + +export default function Page() { + return ( +
+

View pictures

+ {/* Fonctionne, car Carousel est un composant Client */} + +
+ ) +} +``` + +> **Conseil pour les auteurs de bibliothèques** +> +> Si vous créez une bibliothèque de composants, ajoutez la directive `"use client"` aux points d'entrée qui dépendent de fonctionnalités réservées au client. Cela permet à vos utilisateurs d'importer des composants dans des composants Serveur sans avoir besoin de créer des wrappers. +> +> Il est à noter que certains bundlers peuvent supprimer les directives `"use client"`. Vous pouvez trouver un exemple de configuration d'esbuild pour inclure la directive `"use client"` dans les dépôts [React Wrap Balancer](https://github.com/shuding/react-wrap-balancer/blob/main/tsup.config.ts#L10-L13) et [Vercel Analytics](https://github.com/vercel/analytics/blob/main/packages/web/tsup.config.js#L26-L30). + +### Prévenir l'intoxication de l'environnement + +Les modules JavaScript peuvent être partagés entre les modules des composants Serveur et Client. Cela signifie qu'il est possible d'importer accidentellement du code réservé au serveur dans le client. Par exemple, considérez la fonction suivante : + +```ts filename="lib/data.ts" switcher +export async function getData() { + const res = await fetch('https://external-service.com/data', { + headers: { + authorization: process.env.API_KEY, + }, + }) + + return res.json() +} +``` + +```js filename="lib/data.js" switcher +export async function getData() { + const res = await fetch('https://external-service.com/data', { + headers: { + authorization: process.env.API_KEY, + }, + }) + + return res.json() +} +``` + +Cette fonction contient une `API_KEY` qui ne devrait jamais être exposée au client. + +Dans Next.js, seules les variables d'environnement préfixées par `NEXT_PUBLIC_` sont incluses dans le bundle client. Si les variables ne sont pas préfixées, Next.js les remplace par une chaîne vide. + +Par conséquent, même si `getData()` peut être importée et exécutée côté client, elle ne fonctionnera pas comme prévu. + +Pour éviter une utilisation accidentelle dans les composants Client, vous pouvez utiliser le package [`server-only`](https://www.npmjs.com/package/server-only). + +```bash filename="Terminal" +npm install server-only +``` + +Ensuite, importez le package dans un fichier contenant du code réservé au serveur : + +```js filename="lib/data.js" +import 'server-only' + +export async function getData() { + const res = await fetch('https://external-service.com/data', { + headers: { + authorization: process.env.API_KEY, + }, + }) + + return res.json() +} +``` + +Désormais, si vous essayez d'importer ce module dans un composant Client, une erreur sera générée lors de la compilation. + +> **Bon à savoir** : Le package correspondant [`client-only`](https://www.npmjs.com/package/client-only) peut être utilisé pour marquer les modules contenant une logique réservée au client, comme du code accédant à l'objet `window`. diff --git a/apps/docs/content/fr/docs/01-app/01-getting-started/08-fetching-data.mdx b/apps/docs/content/fr/docs/01-app/01-getting-started/08-fetching-data.mdx new file mode 100644 index 00000000..cfcafa55 --- /dev/null +++ b/apps/docs/content/fr/docs/01-app/01-getting-started/08-fetching-data.mdx @@ -0,0 +1,658 @@ +--- +source-updated-at: 2025-06-01T01:32:20.000Z +translation-updated-at: 2025-06-02T20:04:39.188Z +title: Comment récupérer des données et les streamer +nav_title: Récupération de données +description: Commencez à récupérer des données et à streamer du contenu dans votre application. +related: + title: Référence API + description: Apprenez-en plus sur les fonctionnalités mentionnées dans cette page en consultant la référence API. + links: + - app/api-reference/functions/fetch + - app/api-reference/file-conventions/loading + - app/api-reference/config/next-config-js/logging + - app/api-reference/config/next-config-js/taint +--- + +Cette page vous guidera sur la manière de récupérer des données dans les [composants Serveur et Client](/docs/app/getting-started/server-and-client-components), et comment [streamer](#streaming) les composants qui dépendent de données. + +## Récupération de données + +### Composants Serveur + +Vous pouvez récupérer des données dans les composants Serveur en utilisant : + +1. L'[API `fetch`](#avec-lapi-fetch) +2. Un [ORM ou une base de données](#avec-un-orm-ou-une-base-de-données) + +#### Avec l'API `fetch` + +Pour récupérer des données avec l'API `fetch`, transformez votre composant en une fonction asynchrone et utilisez `await` sur l'appel à `fetch`. Par exemple : + +```tsx filename="app/blog/page.tsx" switcher +export default async function Page() { + const data = await fetch('https://api.vercel.app/blog') + const posts = await data.json() + return ( +
    + {posts.map((post) => ( +
  • {post.title}
  • + ))} +
+ ) +} +``` + +```jsx filename="app/blog/page.js" switcher +export default async function Page() { + const data = await fetch('https://api.vercel.app/blog') + const posts = await data.json() + return ( +
    + {posts.map((post) => ( +
  • {post.title}
  • + ))} +
+ ) +} +``` + +> **Bon à savoir :** +> +> - Les réponses de `fetch` ne sont pas mises en cache par défaut. Cependant, Next.js [prérendra](/docs/app/getting-started/partial-prerendering#static-rendering) la route et le résultat sera mis en cache pour améliorer les performances. Si vous souhaitez opter pour un [rendu dynamique](/docs/app/getting-started/partial-prerendering#dynamic-rendering), utilisez l'option `{ cache: 'no-store' }`. Consultez la [référence de l'API `fetch`](/docs/app/api-reference/functions/fetch). +> - Pendant le développement, vous pouvez logger les appels à `fetch` pour une meilleure visibilité et un meilleur débogage. Consultez la [référence de l'API `logging`](/docs/app/api-reference/config/next-config-js/logging). + +#### Avec un ORM ou une base de données + +Comme les composants Serveur sont rendus côté serveur, vous pouvez interroger une base de données en toute sécurité en utilisant un ORM ou un client de base de données. Transformez votre composant en une fonction asynchrone et utilisez `await` sur l'appel : + +```tsx filename="app/blog/page.tsx" switcher +import { db, posts } from '@/lib/db' + +export default async function Page() { + const allPosts = await db.select().from(posts) + return ( +
    + {allPosts.map((post) => ( +
  • {post.title}
  • + ))} +
+ ) +} +``` + +```jsx filename="app/blog/page.js" switcher +import { db, posts } from '@/lib/db' + +export default async function Page() { + const allPosts = await db.select().from(posts) + return ( +
    + {allPosts.map((post) => ( +
  • {post.title}
  • + ))} +
+ ) +} +``` + +### Composants Client + +Il existe deux façons de récupérer des données dans les composants Client, en utilisant : + +1. Le [hook `use` de React](https://react.dev/reference/react/use) +2. Une bibliothèque communautaire comme [SWR](https://swr.vercel.app/) ou [React Query](https://tanstack.com/query/latest) + +#### Streamer des données avec le hook `use` + +Vous pouvez utiliser le [hook `use` de React](https://react.dev/reference/react/use) pour [streamer](#streaming) des données du serveur vers le client. Commencez par récupérer des données dans votre composant Serveur, puis passez la promesse à votre composant Client en tant que prop : + +```tsx filename="app/blog/page.tsx" switcher +import Posts from '@/app/ui/posts +import { Suspense } from 'react' + +export default function Page() { + // Ne pas utiliser await sur la fonction de récupération de données + const posts = getPosts() + + return ( + Loading...}> + + + ) +} +``` + +```jsx filename="app/blog/page.js" switcher +import Posts from '@/app/ui/posts +import { Suspense } from 'react' + +export default function Page() { + // Ne pas utiliser await sur la fonction de récupération de données + const posts = getPosts() + + return ( + Loading...}> + + + ) +} +``` + +Ensuite, dans votre composant Client, utilisez le hook `use` pour lire la promesse : + +```tsx filename="app/ui/posts.tsx" switcher +'use client' +import { use } from 'react' + +export default function Posts({ + posts, +}: { + posts: Promise<{ id: string; title: string }[]> +}) { + const allPosts = use(posts) + + return ( +
    + {allPosts.map((post) => ( +
  • {post.title}
  • + ))} +
+ ) +} +``` + +```jsx filename="app/ui/posts.js" switcher +'use client' +import { use } from 'react' + +export default function Posts({ posts }) { + const posts = use(posts) + + return ( +
    + {posts.map((post) => ( +
  • {post.title}
  • + ))} +
+ ) +} +``` + +Dans l'exemple ci-dessus, le composant `` est enveloppé dans une limite [``](https://react.dev/reference/react/Suspense). Cela signifie que le fallback sera affiché pendant que la promesse est en cours de résolution. Apprenez-en plus sur le [streaming](#streaming). + +#### Bibliothèques communautaires + +Vous pouvez utiliser une bibliothèque communautaire comme [SWR](https://swr.vercel.app/) ou [React Query](https://tanstack.com/query/latest) pour récupérer des données dans les composants Client. Ces bibliothèques ont leurs propres sémantiques pour la mise en cache, le streaming et d'autres fonctionnalités. Par exemple, avec SWR : + +```tsx filename="app/blog/page.tsx" switcher +'use client' +import useSWR from 'swr' + +const fetcher = (url) => fetch(url).then((r) => r.json()) + +export default function BlogPage() { + const { data, error, isLoading } = useSWR( + 'https://api.vercel.app/blog', + fetcher + ) + + if (isLoading) return
Loading...
+ if (error) return
Error: {error.message}
+ + return ( +
    + {data.map((post: { id: string; title: string }) => ( +
  • {post.title}
  • + ))} +
+ ) +} +``` + +```jsx filename="app/blog/page.js" switcher +'use client' + +import useSWR from 'swr' + +const fetcher = (url) => fetch(url).then((r) => r.json()) + +export default function BlogPage() { + const { data, error, isLoading } = useSWR( + 'https://api.vercel.app/blog', + fetcher + ) + + if (isLoading) return
Loading...
+ if (error) return
Error: {error.message}
+ + return ( +
    + {data.map((post) => ( +
  • {post.title}
  • + ))} +
+ ) +} +``` + +## Déduplication des requêtes avec `React.cache` + +La déduplication est le processus de _prévention des requêtes en double_ pour la même ressource pendant un rendu. Elle vous permet de récupérer les mêmes données dans différents composants tout en évitant plusieurs requêtes réseau vers votre source de données. + +Si vous utilisez `fetch`, les requêtes peuvent être dédupliquées en ajoutant `cache: 'force-cache'`. Cela signifie que vous pouvez appeler la même URL avec les mêmes options en toute sécurité, et une seule requête sera effectuée. + +Si vous _n'utilisez pas_ `fetch`, mais plutôt un ORM ou une base de données directement, vous pouvez envelopper votre récupération de données avec la fonction [React `cache`](https://react.dev/reference/react/cache). + +```tsx filename="app/lib/data.ts" switcher +import { cache } from 'react' +import { db, posts, eq } from '@/lib/db' + +export const getPost = cache(async (id: string) => { + const post = await db.query.posts.findFirst({ + where: eq(posts.id, parseInt(id)), + }) +}) +``` + +```jsx filename="app/lib/data.js" switcher +import { cache } from 'react' +import { db, posts, eq } from '@/lib/db' +import { notFound } from 'next/navigation' + +export const getPost = cache(async (id) => { + const post = await db.query.posts.findFirst({ + where: eq(posts.id, parseInt(id)), + }) +}) +``` + +## Streaming + +> **Avertissement :** Le contenu ci-dessous suppose que l'option de configuration [`dynamicIO`](/docs/app/api-reference/config/next-config-js/dynamicIO) est activée dans votre application. Ce drapeau a été introduit dans Next.js 15 canary. + +Lorsque vous utilisez `async/await` dans les composants Serveur, Next.js optera pour un [rendu dynamique](/docs/app/getting-started/partial-prerendering#dynamic-rendering). Cela signifie que les données seront récupérées et rendues côté serveur pour chaque requête utilisateur. S'il y a des requêtes de données lentes, toute la route sera bloquée pour le rendu. + +Pour améliorer le temps de chargement initial et l'expérience utilisateur, vous pouvez utiliser le streaming pour diviser le HTML de la page en petits morceaux et les envoyer progressivement du serveur vers le client. + +Fonctionnement du rendu côté serveur avec streaming + +Il existe deux façons d'implémenter le streaming dans votre application : + +1. En enveloppant une page avec un [fichier `loading.js`](#avec-loadingjs) +2. En enveloppant un composant avec [``](#avec-suspense) + +### Avec `loading.js` + +Vous pouvez créer un fichier `loading.js` dans le même dossier que votre page pour streamer **toute la page** pendant que les données sont en cours de récupération. Par exemple, pour streamer `app/blog/page.js`, ajoutez le fichier dans le dossier `app/blog`. + +Structure du dossier Blog avec fichier loading.js + +```tsx filename="app/blog/loading.tsx" switcher +export default function Loading() { + // Définissez l'interface utilisateur de chargement ici + return
Loading...
+} +``` + +```jsx filename="app/blog/loading.js" switcher +export default function Loading() { + // Définissez l'interface utilisateur de chargement ici + return
Loading...
+} +``` + +Lors de la navigation, l'utilisateur verra immédiatement la mise en page et un [état de chargement](#creation-detats-de-chargement-significatifs) pendant que la page est en cours de rendu. Le nouveau contenu sera automatiquement remplacé une fois le rendu terminé. + +Interface utilisateur de chargement + +En arrière-plan, `loading.js` sera imbriqué dans `layout.js` et enveloppera automatiquement le fichier `page.js` et tous les enfants en dessous dans une limite ``. + +Aperçu de loading.js + +Cette approche fonctionne bien pour les segments de route (layouts et pages), mais pour un streaming plus granulaire, vous pouvez utiliser ``. + +### Avec `` + +`` vous permet d'être plus précis sur les parties de la page à streamer. Par exemple, vous pouvez immédiatement afficher tout contenu de page qui se trouve en dehors de la limite ``, et streamer la liste des articles de blog à l'intérieur de la limite. + +```tsx filename="app/blog/page.tsx" switcher +import { Suspense } from 'react' +import BlogList from '@/components/BlogList' +import BlogListSkeleton from '@/components/BlogListSkeleton' + +export default function BlogPage() { + return ( +
+ {/* Ce contenu sera envoyé au client immédiatement */} +
+

Bienvenue sur le Blog

+

Lisez les derniers articles ci-dessous.

+
+
+ {/* Tout contenu enveloppé dans une limite sera streamé */} + }> + + +
+
+ ) +} +``` + +```jsx filename="app/blog/page.js" switcher +import { Suspense } from 'react' +import BlogList from '@/components/BlogList' +import BlogListSkeleton from '@/components/BlogListSkeleton' + +export default function BlogPage() { + return ( +
+ {/* Ce contenu sera envoyé au client immédiatement */} +
+

Bienvenue sur le Blog

+

Lisez les derniers articles ci-dessous.

+
+
+ {/* Tout contenu enveloppé dans une limite sera streamé */} + }> + + +
+
+ ) +} +``` + +### Création d'états de chargement significatifs + +Un état de chargement instantané est une interface utilisateur de fallback qui est affichée immédiatement à l'utilisateur après la navigation. Pour la meilleure expérience utilisateur, nous recommandons de concevoir des états de chargement qui sont significatifs et aident les utilisateurs à comprendre que l'application répond. Par exemple, vous pouvez utiliser des squelettes et des spinners, ou une petite partie significative des écrans futurs comme une photo de couverture, un titre, etc. + +En développement, vous pouvez prévisualiser et inspecter l'état de chargement de vos composants en utilisant les [React Devtools](https://react.dev/learn/react-developer-tools). + +## Exemples + +### Récupération séquentielle de données + +La récupération séquentielle de données se produit lorsque des composants imbriqués dans un arbre récupèrent chacun leurs propres données et que les requêtes ne sont pas [dédupliquées](/docs/app/deep-dive/caching#request-memoization), ce qui entraîne des temps de réponse plus longs. + +Récupération séquentielle et parallèle de données + +Il peut y avoir des cas où vous voulez ce modèle parce qu'une récupération dépend du résultat de l'autre. + +Par exemple, le composant `` ne commencera à récupérer des données que lorsque le composant `` aura terminé de récupérer des données, car `` dépend de la prop `artistID` : + +```tsx filename="app/artist/[username]/page.tsx" switcher +export default async function Page({ + params, +}: { + params: Promise<{ username: string }> +}) { + const { username } = await params + // Récupérer les informations de l'artiste + const artist = await getArtist(username) + + return ( + <> +

{artist.name}

+ {/* Afficher une interface utilisateur de fallback pendant que le composant Playlists charge */} + Loading...}> + {/* Passer l'ID de l'artiste au composant Playlists */} + + + + ) +} + +async function Playlists({ artistID }: { artistID: string }) { + // Utiliser l'ID de l'artiste pour récupérer les playlists + const playlists = await getArtistPlaylists(artistID) + + return ( +
    + {playlists.map((playlist) => ( +
  • {playlist.name}
  • + ))} +
+ ) +} +``` + +```jsx filename="app/artist/[username]/page.js" switcher +export default async function Page({ params }) { + const { username } = await params + // Récupérer les informations de l'artiste + const artist = await getArtist(username) + + return ( + <> +

{artist.name}

+ {/* Afficher une interface utilisateur de fallback pendant que le composant Playlists charge */} + Loading...}> + {/* Passer l'ID de l'artiste au composant Playlists */} + + + + ) +} + +async function Playlists({ artistID }) { + // Utiliser l'ID de l'artiste pour récupérer les playlists + const playlists = await getArtistPlaylists(artistID) + + return ( +
    + {playlists.map((playlist) => ( +
  • {playlist.name}
  • + ))} +
+ ) +} +``` + +Pour améliorer l'expérience utilisateur, vous devez utiliser [React ``](/docs/app/building-your-application/routing/loading-ui-and-streaming#streaming-with-suspense) pour afficher un `fallback` pendant que les données sont en cours de récupération. Cela permettra le [streaming](#streaming) et empêchera que toute la route soit bloquée par les requêtes de données séquentielles. + +### Récupération de données en parallèle + +La récupération de données en parallèle se produit lorsque les requêtes de données dans une route sont initiées de manière anticipée et démarrent en même temps. + +Par défaut, [les layouts et les pages](/docs/app/getting-started/layouts-and-pages) sont rendus en parallèle. Ainsi, chaque segment commence à récupérer les données dès que possible. + +Cependant, dans _n'importe quel_ composant, plusieurs requêtes `async`/`await` peuvent toujours être séquentielles si elles sont placées les unes après les autres. Par exemple, `getAlbums` sera bloqué jusqu'à ce que `getArtist` soit résolu : + +```tsx filename="app/artist/[username]/page.tsx" switcher +import { getArtist, getAlbums } from '@/app/lib/data' + +export default async function Page({ params }) { + // Ces requêtes seront séquentielles + const { username } = await params + const artist = await getArtist(username) + const albums = await getAlbums(username) + return
{artist.name}
+} +``` + +Vous pouvez initier les requêtes en parallèle en les définissant en dehors des composants qui utilisent les données, et en les résolvant ensemble, par exemple avec [`Promise.all`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all) : + +```tsx filename="app/artist/[username]/page.tsx" highlight={3,8,23} switcher +import Albums from './albums' + +async function getArtist(username: string) { + const res = await fetch(`https://api.example.com/artist/${username}`) + return res.json() +} + +async function getAlbums(username: string) { + const res = await fetch(`https://api.example.com/artist/${username}/albums`) + return res.json() +} + +export default async function Page({ + params, +}: { + params: Promise<{ username: string }> +}) { + const { username } = await params + const artistData = getArtist(username) + const albumsData = getAlbums(username) + + // Initie les deux requêtes en parallèle + const [artist, albums] = await Promise.all([artistData, albumsData]) + + return ( + <> +

{artist.name}

+ + + ) +} +``` + +```jsx filename="app/artist/[username]/page.js" highlight={3,8,19} switcher +import Albums from './albums' + +async function getArtist(username) { + const res = await fetch(`https://api.example.com/artist/${username}`) + return res.json() +} + +async function getAlbums(username) { + const res = await fetch(`https://api.example.com/artist/${username}/albums`) + return res.json() +} + +export default async function Page({ params }) { + const { username } = await params + const artistData = getArtist(username) + const albumsData = getAlbums(username) + + // Initie les deux requêtes en parallèle + const [artist, albums] = await Promise.all([artistData, albumsData]) + + return ( + <> +

{artist.name}

+ + + ) +} +``` + +> **Bon à savoir :** Si une requête échoue lors de l'utilisation de `Promise.all`, l'ensemble de l'opération échouera. Pour gérer cela, vous pouvez utiliser la méthode [`Promise.allSettled`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled) à la place. + +### Préchargement des données + +Vous pouvez précharger les données en créant une fonction utilitaire que vous appelez de manière anticipée avant les requêtes bloquantes. `` s'affiche conditionnellement en fonction de la fonction `checkIsAvailable()`. + +Vous pouvez appeler `preload()` avant `checkIsAvailable()` pour initier de manière anticipée les dépendances de données de ``. Au moment où `` est rendu, ses données ont déjà été récupérées. + +```tsx filename="app/item/[id]/page.tsx" switcher +import { getItem } from '@/lib/data' + +export default async function Page({ + params, +}: { + params: Promise<{ id: string }> +}) { + const { id } = await params + // commence le chargement des données de l'item + preload(id) + // effectue une autre tâche asynchrone + const isAvailable = await checkIsAvailable() + + return isAvailable ? : null +} + +export const preload = (id: string) => { + // void évalue l'expression donnée et retourne undefined + // https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/void + void getItem(id) +} +export async function Item({ id }: { id: string }) { + const result = await getItem(id) + // ... +} +``` + +```jsx filename="app/item/[id]/page.js" switcher +import { getItem } from '@/lib/data' + +export default async function Page({ params }) { + const { id } = await params + // commence le chargement des données de l'item + preload(id) + // effectue une autre tâche asynchrone + const isAvailable = await checkIsAvailable() + + return isAvailable ? : null +} + +export const preload = (id) => { + // void évalue l'expression donnée et retourne undefined + // https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/void + void getItem(id) +} +export async function Item({ id }) { + const result = await getItem(id) + // ... +``` + +De plus, vous pouvez utiliser la fonction [`cache` de React](https://react.dev/reference/react/cache) et le package [`server-only`](https://www.npmjs.com/package/server-only) pour créer une fonction utilitaire réutilisable. Cette approche vous permet de mettre en cache la fonction de récupération de données et de vous assurer qu'elle n'est exécutée que sur le serveur. + +```ts filename="utils/get-item.ts" switcher +import { cache } from 'react' +import 'server-only' +import { getItem } from '@/lib/data' + +export const preload = (id: string) => { + void getItem(id) +} + +export const getItem = cache(async (id: string) => { + // ... +}) +``` + +```js filename="utils/get-item.js" switcher +import { cache } from 'react' +import 'server-only' +import { getItem } from '@/lib/data' + +export const preload = (id) => { + void getItem(id) +} + +export const getItem = cache(async (id) => { + // ... +}) +``` diff --git a/apps/docs/content/fr/docs/01-app/01-getting-started/09-caching-and-revalidating.mdx b/apps/docs/content/fr/docs/01-app/01-getting-started/09-caching-and-revalidating.mdx new file mode 100644 index 00000000..b9f1bea5 --- /dev/null +++ b/apps/docs/content/fr/docs/01-app/01-getting-started/09-caching-and-revalidating.mdx @@ -0,0 +1,252 @@ +--- +source-updated-at: 2025-06-01T01:32:20.000Z +translation-updated-at: 2025-06-02T20:01:56.984Z +title: Comment mettre en cache et revalider les données +nav_title: Cache et revalidation +description: Apprenez à mettre en cache et revalider les données dans votre application. +related: + title: Référence API + description: En savoir plus sur les fonctionnalités mentionnées dans cette page en consultant la référence API. + links: + - app/api-reference/functions/fetch + - app/api-reference/functions/unstable_cache + - app/api-reference/functions/revalidatePath + - app/api-reference/functions/revalidateTag +--- + +La mise en cache (caching) est une technique qui consiste à stocker le résultat de récupération de données et d'autres calculs afin que les requêtes futures pour les mêmes données puissent être servies plus rapidement, sans avoir à refaire le travail. La revalidation vous permet quant à elle de mettre à jour les entrées du cache sans avoir à reconstruire entièrement votre application. + +Next.js fournit plusieurs API pour gérer la mise en cache et la revalidation. Ce guide vous expliquera quand et comment les utiliser. + +- [`fetch`](#fetch) +- [`unstable_cache`](#unstable_cache) +- [`revalidatePath`](#revalidatepath) +- [`revalidateTag`](#revalidatetag) + +## `fetch` + +Par défaut, les requêtes [`fetch`](/docs/app/api-reference/functions/fetch) ne sont pas mises en cache. Vous pouvez mettre en cache des requêtes individuelles en définissant l'option `cache` sur `'force-cache'`. + +```tsx filename="app/page.tsx" switcher +export default async function Page() { + const data = await fetch('https://...', { cache: 'force-cache' }) +} +``` + +```jsx filename="app/page.jsx" switcher +export default async function Page() { + const data = await fetch('https://...', { cache: 'force-cache' }) +} +``` + +> **Bon à savoir** : Bien que les requêtes `fetch` ne soient pas mises en cache par défaut, Next.js effectuera un [prérendu (prerender)](/docs/app/getting-started/partial-prerendering#static-rendering) des routes contenant des requêtes `fetch` et mettra en cache le HTML. Si vous souhaitez garantir qu'une route est [dynamique](/docs/app/getting-started/partial-prerendering#dynamic-rendering), utilisez l'[API `connection`](/docs/app/api-reference/functions/connection). + +Pour revalider les données retournées par une requête `fetch`, vous pouvez utiliser l'option `next.revalidate`. + +```tsx filename="app/page.tsx" switcher +export default async function Page() { + const data = await fetch('https://...', { next: { revalidate: 3600 } }) +} +``` + +```jsx filename="app/page.jsx" switcher +export default async function Page() { + const data = await fetch('https://...', { next: { revalidate: 3600 } }) +} +``` + +Cela revalidera les données après un nombre spécifié de secondes. + +Consultez la [référence API de `fetch`](/docs/app/api-reference/functions/fetch) pour en savoir plus. + +## `unstable_cache` + +`unstable_cache` vous permet de mettre en cache le résultat de requêtes de base de données et d'autres fonctions asynchrones. Pour l'utiliser, enveloppez `unstable_cache` autour de la fonction. Par exemple : + +```tsx filename="app/lib/data.ts swichter +import { db } from '@/lib/db' +export async function getUserById(id: string) { + return db + .select() + .from(users) + .where(eq(users.id, id)) + .then((res) => res[0]) +} +``` + +```jsx filename="app/lib/data.js" switcher +import { db } from '@/lib/db' + +export async function getUserById(id) { + return db + .select() + .from(users) + .where(eq(users.id, id)) + .then((res) => res[0]) +} +``` + +```tsx filename="app/page.tsx" highlight={2,11,13} switcher +import { unstable_cache } from 'next/cache' +import { getUserById } from '@/app/lib/data' + +export default async function Page({ + params, +}: { + params: Promise<{ userId: string }> +}) { + const { userId } = await params + + const getCachedUser = unstable_cache( + async () => { + return getUserById(userId) + }, + [userId] // ajoute l'ID utilisateur à la clé de cache + ) +} +``` + +```jsx filename="app/page.jsx" highlight={2,7,9} switcher +import { unstable_cache } from 'next/cache'; +import { getUserById } from '@/app/lib/data'; + +export default async function Page({ params } }) { + const { userId } = await params + + const getCachedUser = unstable_cache( + async () => { + return getUserById(userId) + }, + [userId] // ajoute l'ID utilisateur à la clé de cache + ); +} +``` + +La fonction accepte un troisième objet optionnel pour définir comment le cache doit être revalidé. Il accepte : + +- `tags` : un tableau d'étiquettes (tags) utilisées par Next.js pour revalider le cache. +- `revalidate` : le nombre de secondes après lesquelles le cache doit être revalidé. + +```tsx filename="app/page.tsx" highlight={6-9} switcher +const getCachedUser = unstable_cache( + async () => { + return getUserById(userId) + }, + [userId], + { + tags: ['user'], + revalidate: 3600, + } +) +``` + +```jsx filename="app/page.js" highlight={6-9} switcher +const getCachedUser = unstable_cache( + async () => { + return getUserById(userId) + }, + [userId], + { + tags: ['user'], + revalidate: 3600, + } +) +``` + +Consultez la [référence API de `unstable_cache`](/docs/app/api-reference/functions/unstable_cache) pour en savoir plus. + +## `revalidateTag` + +`revalidateTag` est utilisé pour revalider des entrées de cache basées sur une étiquette (tag) suite à un événement. Pour l'utiliser avec `fetch`, commencez par étiqueter la fonction avec l'option `next.tags` : + +```tsx filename="app/lib/data.ts" highlight={3-5} switcher +export async function getUserById(id: string) { + const data = await fetch(`https://...`, { + next: { + tags: ['user'], + }, + }) +} +``` + +```jsx filename="app/lib/data.js" highlight={3-5} switcher +export async function getUserById(id) { + const data = await fetch(`https://...`, { + next: { + tags: ['user'], + }, + }) +} +``` + +Alternativement, vous pouvez marquer une fonction `unstable_cache` avec l'option `tags` : + +```tsx filename="app/lib/data.ts" highlight={6-8} switcher +export const getUserById = unstable_cache( + async (id: string) => { + return db.query.users.findFirst({ where: eq(users.id, id) }) + }, + ['user'], // Nécessaire si les variables ne sont pas passées en paramètres + { + tags: ['user'], + } +) +``` + +```jsx filename="app/lib/data.js" highlight={6-8} switcher +export const getUserById = unstable_cache( + async (id) => { + return db.query.users.findFirst({ where: eq(users.id, id) }) + }, + ['user'], // Nécessaire si les variables ne sont pas passées en paramètres + { + tags: ['user'], + } +) +``` + +Puis, appelez `revalidateTag` dans un [Route Handler](/docs/app/api-reference/file-conventions/route) ou une Server Action : + +```tsx filename="app/lib/actions.ts" highlight={1} switcher +import { revalidateTag } from 'next/cache' + +export async function updateUser(id: string) { + // Modifier les données + revalidateTag('user') +} +``` + +```jsx filename="app/lib/actions.js" highlight={1} switcher +import { revalidateTag } from 'next/cache' + +export async function updateUser(id) { + // Modifier les données + revalidateTag('user') +} +``` + +Vous pouvez réutiliser la même étiquette dans plusieurs fonctions pour toutes les revalider en une seule fois. + +Consultez la [référence API de `revalidateTag`](/docs/app/api-reference/functions/revalidateTag) pour en savoir plus. + +## `revalidatePath` + +`revalidatePath` est utilisé pour revalider une route suite à un événement. Pour l'utiliser, appelez-le dans un [Route Handler](/docs/app/api-reference/file-conventions/route) ou une Server Action : + +```tsx filename="app/lib/actions.ts" highlight={1} switcher +import { revalidatePath } from 'next/cache' + +export async function updateUser(id: string) { + // Modifier les données + revalidatePath('/profile') +``` + +```jsx filename="app/lib/actions.js" highlight={1} switcher +import { revalidatePath } from 'next/cache' + +export async function updateUser(id) { + // Modifier les données + revalidatePath('/profile') +``` + +Consultez la [référence API de `revalidatePath`](/docs/app/api-reference/functions/revalidatePath) pour en savoir plus. \ No newline at end of file diff --git a/apps/docs/content/fr/docs/01-app/01-getting-started/10-updating-data.mdx b/apps/docs/content/fr/docs/01-app/01-getting-started/10-updating-data.mdx new file mode 100644 index 00000000..adf3850c --- /dev/null +++ b/apps/docs/content/fr/docs/01-app/01-getting-started/10-updating-data.mdx @@ -0,0 +1,352 @@ +--- +source-updated-at: 2025-06-01T01:32:20.000Z +translation-updated-at: 2025-06-02T20:02:02.492Z +title: Comment mettre à jour les données +nav_title: Mise à jour des données +description: Apprenez comment mettre à jour les données dans votre application Next.js. +related: + title: Référence API + description: En savoir plus sur les fonctionnalités mentionnées dans cette page en consultant la référence API. + links: + - app/api-reference/functions/revalidatePath + - app/api-reference/functions/revalidateTag + - app/api-reference/functions/redirect +--- + +Vous pouvez mettre à jour les données dans Next.js en utilisant les [Fonctions Serveur (Server Functions)](https://react.dev/reference/rsc/server-functions) de React. Cette page explique comment [créer](#creating-server-functions) et [invoquer](#invoking-server-functions) des Fonctions Serveur. + +## Fonctions Serveur + +Une Fonction Serveur est une fonction asynchrone exécutée sur le serveur. Les Fonctions Serveur sont intrinsèquement asynchrones car elles sont invoquées par le client via une requête réseau. Lorsqu'elles sont invoquées dans le cadre d'une `action`, elles sont également appelées **Actions Serveur (Server Actions)**. + +Par convention, une `action` est une fonction asynchrone passée à `startTransition`. Les Fonctions Serveur sont automatiquement encapsulées avec `startTransition` lorsque : + +- Elles sont passées à un `
` via la prop `action`, +- Elles sont passées à un ` +} +``` + +```jsx filename="app/ui/button.js" switcher +'use client' + +import { createPost } from '@/app/actions' + +export function Button() { + return +} +``` + +## Invocation de Fonctions Serveur + +Il existe deux principales façons d'invoquer une Fonction Serveur : + +1. [Formulaires](#forms) dans les Composants Serveur et Client +2. [Gestionnaires d'événements](#event-handlers) dans les Composants Client + +### Formulaires + +React étend l'élément HTML [``](https://react.dev/reference/react-dom/components/form) pour permettre l'invocation d'une Fonction Serveur avec la prop HTML `action`. + +Lorsqu'elle est invoquée dans un formulaire, la fonction reçoit automatiquement l'objet [`FormData`](https://developer.mozilla.org/docs/Web/API/FormData/FormData). Vous pouvez extraire les données en utilisant les [méthodes natives de `FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData#instance_methods) : + +```tsx filename="app/ui/form.tsx" switcher +import { createPost } from '@/app/actions' + +export function Form() { + return ( + + + + +
+ ) +} +``` + +```jsx filename="app/ui/form.js" switcher +import { createPost } from '@/app/actions' + +export function Form() { + return ( +
+ + + +
+ ) +} +``` + +```ts filename="app/actions.ts" switcher +'use server' + +export async function createPost(formData: FormData) { + const title = formData.get('title') + const content = formData.get('content') + + // Mettre à jour les données + // Revalider le cache +} +``` + +```js filename="app/actions.js" switcher +'use server' + +export async function createPost(formData) { + const title = formData.get('title') + const content = formData.get('content') + + // Mettre à jour les données + // Revalider le cache +} +``` + +> **Bon à savoir :** Lorsqu'elle est passée à la prop `action`, les Fonctions Serveur sont également appelées _Actions Serveur (Server Actions)_. + +### Gestionnaires d'événements + +Vous pouvez invoquer une Fonction Serveur dans un Composant Client en utilisant des gestionnaires d'événements comme `onClick`. + +```tsx filename="app/like-button.tsx" switcher +'use client' + +import { incrementLike } from './actions' +import { useState } from 'react' + +export default function LikeButton({ initialLikes }: { initialLikes: number }) { + const [likes, setLikes] = useState(initialLikes) + + return ( + <> +

Total Likes : {likes}

+ + + ) +} +``` + +```jsx filename="app/like-button.js" switcher +'use client' + +import { incrementLike } from './actions' +import { useState } from 'react' + +export default function LikeButton({ initialLikes }) { + const [likes, setLikes] = useState(initialLikes) + + return ( + <> +

Total Likes : {likes}

+ + + ) +} +``` + +## Exemples + +### Affichage d'un état en attente + +Pendant l'exécution d'une Fonction Serveur, vous pouvez afficher un indicateur de chargement avec le hook [`useActionState`](https://react.dev/reference/react/useActionState) de React. Ce hook retourne un booléen `pending` : + +```tsx filename="app/ui/button.tsx" switcher +'use client' + +import { useActionState } from 'react' +import { createPost } from '@/app/actions' +import { LoadingSpinner } from '@/app/ui/loading-spinner' + +export function Button() { + const [state, action, pending] = useActionState(createPost, false) + + return ( + + ) +} +``` + +```jsx filename="app/ui/button.js" switcher +'use client' + +import { useActionState } from 'react' +import { createPost } from '@/app/actions' +import { LoadingSpinner } from '@/app/ui/loading-spinner' + +export function Button() { + const [state, action, pending] = useActionState(createPost, false) + + return ( + + ) +} +``` + +### Revalidation du cache + +Après avoir effectué une mise à jour, vous pouvez revalider le cache de Next.js et afficher les données mises à jour en appelant [`revalidatePath`](/docs/app/api-reference/functions/revalidatePath) ou [`revalidateTag`](/docs/app/api-reference/functions/revalidateTag) dans la Fonction Serveur : + +```ts filename="app/lib/actions.ts" switcher +import { revalidatePath } from 'next/cache' + +export async function createPost(formData: FormData) { + 'use server' + // Mettre à jour les données + // ... + + revalidatePath('/posts') +} +``` + +```js filename="app/actions.js" switcher +import { revalidatePath } from 'next/cache' + +export async function createPost(formData) { + 'use server' + // Mettre à jour les données + // ... + revalidatePath('/posts') +} +``` + +### Redirection + +Vous pouvez rediriger l'utilisateur vers une autre page après avoir effectué une mise à jour. Pour ce faire, appelez [`redirect`](/docs/app/api-reference/functions/redirect) dans la Fonction Serveur : + +```ts filename="app/lib/actions.ts" switcher +'use server' + +import { redirect } from 'next/navigation' + +export async function createPost(formData: FormData) { + // Mettre à jour les données + // ... + + redirect('/posts') +} +``` + +```js filename="app/actions.js" switcher +'use server' + +import { redirect } from 'next/navigation' + +export async function createPost(formData) { + // Mettre à jour les données + // ... + + redirect('/posts') +} +``` \ No newline at end of file diff --git a/apps/docs/content/fr/docs/01-app/01-getting-started/11-error-handling.mdx b/apps/docs/content/fr/docs/01-app/01-getting-started/11-error-handling.mdx new file mode 100644 index 00000000..429473ef --- /dev/null +++ b/apps/docs/content/fr/docs/01-app/01-getting-started/11-error-handling.mdx @@ -0,0 +1,317 @@ +--- +source-updated-at: 2025-06-01T01:32:20.000Z +translation-updated-at: 2025-06-02T20:01:53.713Z +title: Gestion des erreurs +nav_title: Gestion des erreurs +description: Apprenez à afficher les erreurs attendues et à gérer les exceptions non capturées. +related: + title: Référence API + description: En savoir plus sur les fonctionnalités mentionnées dans cette page en consultant la référence API. + links: + - app/api-reference/functions/redirect + - app/api-reference/file-conventions/error + - app/api-reference/functions/not-found + - app/api-reference/file-conventions/not-found +--- + +Les erreurs peuvent être divisées en deux catégories : [erreurs attendues](#handling-expected-errors) et [exceptions non capturées](#handling-uncaught-exceptions). Cette page vous expliquera comment gérer ces erreurs dans votre application Next.js. + +## Gestion des erreurs attendues + +Les erreurs attendues sont celles qui peuvent survenir lors du fonctionnement normal de l'application, comme celles provenant de [la validation côté serveur de formulaires](/docs/app/guides/forms) ou de requêtes échouées. Ces erreurs doivent être gérées explicitement et renvoyées au client. + +### Fonctions serveur + +Vous pouvez utiliser le hook [`useActionState`](https://react.dev/reference/react/useActionState) pour gérer les erreurs attendues dans les [Fonctions serveur](https://react.dev/reference/rsc/server-functions). + +Pour ces erreurs, évitez d'utiliser des blocs `try`/`catch` et de lancer des erreurs. Modélisez plutôt les erreurs attendues comme des valeurs de retour. + +```ts filename="app/actions.ts" switcher +'use server' + +export async function createPost(prevState: any, formData: FormData) { + const title = formData.get('title') + const content = formData.get('content') + + const res = await fetch('https://api.vercel.app/posts', { + method: 'POST', + body: { title, content }, + }) + const json = await res.json() + + if (!res.ok) { + return { message: 'Failed to create post' } + } +} +``` + +```js filename="app/actions.js" switcher +'use server' + +export async function createPost(prevState, formData) { + const title = formData.get('title') + const content = formData.get('content') + + const res = await fetch('https://api.vercel.app/posts', { + method: 'POST', + body: { title, content }, + }) + const json = await res.json() + + if (!res.ok) { + return { message: 'Failed to create post' } + } +} +``` + +Vous pouvez passer votre action au hook `useActionState` et utiliser l'état (`state`) retourné pour afficher un message d'erreur. + +```tsx filename="app/ui/form.tsx" highlight={11,19} switcher +'use client' + +import { useActionState } from 'react' +import { createPost } from '@/app/actions' + +const initialState = { + message: '', +} + +export function Form() { + const [state, formAction, pending] = useActionState(createPost, initialState) + + return ( +
+ + + +