Cours Next.js · Module 1: Configuration de Next.js
Structure des répertoires et des fichiers dans Next.js (app/ vs pages/)
Dans cette leçon9
À Quantum Metropolis, les ingénieurs conçoivent des systèmes de transport avancés capables de fonctionner aussi bien sur les routes classiques que sur les nouvelles voies de téléportation quantique. De même, Next.js propose deux systèmes de routage parallèles : le Pages Router traditionnel et l'App Router moderne. Dans ce module, nous analyserons en profondeur les différences entre ces deux approches et comprendrons comment organiser les fichiers et les répertoires dans nos projets.
Deux philosophies de routage dans Next.js
Next.js reposait à l'origine sur un routage basé sur les fichiers du dossier pages/. Dans Next.js 13, un nouveau système de routage basé sur le dossier app/ a été introduit. Cette évolution ressemble au passage des systèmes de transport classiques à la téléportation quantique à Quantum Metropolis - la nouvelle technologie est plus avancée, mais les deux coexistent encore.
Pages Router : l'approche classique
Le Pages Router est le système de routage d'origine de Next.js. Il est simple, bien documenté et encore largement utilisé. Dans cette convention, chaque fichier JavaScript ou TypeScript du répertoire pages/ devient automatiquement une route de l'application.
1pages/
2├── index.js # Route: /
3├── about.js # Route: /about
4├── contact.tsx # Route: /contact
5├── products/
6│ ├── index.js # Route: /products
7│ └── [id].js # Route: /products/:id (dynamic)
8└── api/
9 └── hello.js # API Endpoint: /api/helloDans ce système :
- Les fichiers correspondent directement aux chemins d'URL
- Les segments de chemin dynamiques sont indiqués entre crochets
[param] - Un répertoire spécial
api/est utilisé pour gérer les points d'accès API - Chaque fichier exporte par défaut un composant React ou une fonction de gestion d'API
App Router : l'approche moderne
L'App Router, introduit dans Next.js 13 et perfectionné dans la version 15, représente une nouvelle approche basée sur les React Server Components. C'est comme passer des véhicules traditionnels à la téléportation quantique - un changement fondamental dans la façon de concevoir les applications web.
1app/
2├── layout.tsx # Main layout (required)
3├── page.tsx # Route: /
4├── about/
5│ └── page.tsx # Route: /about
6├── blog/
7│ ├── page.tsx # Route: /blog
8│ ├── layout.tsx # Layout specific to /blog and its sub-routes
9│ └── [slug]/
10│ └── page.tsx # Route: /blog/:slug (dynamic)
11└── api/
12 └── users/
13 └── route.ts # API Endpoint: /api/usersDans l'App Router :
- Seuls les répertoires définissent les routes, et des fichiers spéciaux à l'intérieur de ces répertoires remplissent des fonctions précises
- Le fichier
page.tsxrend le composant de page pour une route donnée - Le fichier
layout.tsxdéfinit un layout partagé pour toutes les pages du répertoire et de ses sous-répertoires - Les segments dynamiques utilisent toujours des crochets :
[param] - Les points d'accès API sont créés à l'aide de fichiers
route.ts
Nommage des fichiers et conventions dans l'App Router
L'App Router introduit la « convention plutôt que la configuration » avec une série de fichiers spéciaux qui ont des rôles précis. C'est comme les modules spécialisés des systèmes de Quantum Metropolis - chacun avec une fonction définie dans l'architecture globale.
Fichiers spéciaux de base :
page.tsx : rend l'interface utilisateur de la route et rend le chemin accessible publiquement.
1// app/dashboard/page.tsx 2export default function DashboardPage() { 3 return ( 4 <section> 5 <h1>Quantum Metropolis Control Panel</h1> 6 <p>Welcome to the command center!</p> 7 </section> 8 ); 9}layout.tsx : définit une interface partagée pour un segment et ses enfants.
1// app/dashboard/layout.tsx 2export default function DashboardLayout({ 3 children, 4}: { 5 children: React.ReactNode; 6}) { 7 return ( 8 <div className="dashboard-layout"> 9 <nav className="dashboard-sidebar"> 10 {/* Sidebar navigation */} 11 </nav> 12 <main className="dashboard-main">{children}</main> 13 </div> 14 ); 15}route.ts : crée un point d'accès API à l'aide de la nouvelle API de gestion des requêtes.
1// app/api/status/route.ts 2import { NextResponse } from 'next/server'; 3 4export async function GET() { 5 return NextResponse.json({ 6 status: 'online', 7 systemsOperational: 15, 8 time: new Date().toISOString() 9 }); 10} 11 12export async function POST(request: Request) { 13 const data = await request.json(); 14 // Processing data... 15 return NextResponse.json({ success: true }); 16}loading.tsx : crée une interface de chargement avec React Suspense.
1// app/dashboard/loading.tsx 2export default function DashboardLoading() { 3 return ( 4 <div className="dashboard-loading"> 5 <div className="spinner"></div> 6 <p>Loading Metropolis system data...</p> 7 </div> 8 ); 9}error.tsx : crée une interface de gestion des erreurs avec React Error Boundary.
1'use client'; // Error handling components must be client components 2 3import { useEffect } from 'react'; 4 5export default function DashboardError({ 6 error, 7 reset, 8}: { 9 error: Error; 10 reset: () => void; 11}) { 12 useEffect(() => { 13 // Log error to monitoring system 14 console.error(error); 15 }, [error]); 16 17 return ( 18 <div className="error-container"> 19 <h2>An error occurred in the Metropolis systems!</h2> 20 <p>{error.message}</p> 21 <button onClick={reset}>Try again</button> 22 </div> 23 ); 24}not-found.tsx : crée une interface pour une ressource introuvable (404).
1// app/not-found.tsx 2export default function NotFound() { 3 return ( 4 <div className="not-found"> 5 <h2>Unknown Zone</h2> 6 <p>No Quantum Metropolis module was found with that identifier.</p> 7 <a href="/">Return to command center</a> 8 </div> 9 ); 10}
Fonctionnalités avancées de l'App Router
L'App Router introduit plusieurs fonctionnalités d'organisation avancées qui ressemblent aux systèmes de transport avancés de Quantum Metropolis - elles permettent des routes plus complexes et plus flexibles.
1. Route Groups (groupes de routes)
Les groupes de routes permettent d'organiser les fichiers sans affecter la structure de l'URL. Ils sont indiqués en encadrant le nom du répertoire entre parenthèses : (group-name).
1app/
2├── (marketing)/ # Route group (does not affect URL path)
3│ ├── about/
4│ │ └── page.tsx # Route: /about
5│ └── contact/
6│ └── page.tsx # Route: /contact
7└── (dashboard)/ # Another route group
8 ├── layout.tsx # Shared layout for dashboard routes
9 ├── page.tsx # Route: /
10 └── stats/
11 └── page.tsx # Route: /statsLes groupes de routes sont comme les quartiers de Quantum Metropolis - ils aident à organiser la structure de la ville, mais n'affectent pas les adresses.
2. Parallel Routes (routes parallèles)
Les routes parallèles permettent de rendre simultanément plusieurs pages dans la même vue, ce qui est utile pour les layouts complexes. Elles sont indiquées par un nom de slot précédé du signe « @ » : @slot-name.
1app/
2├── layout.tsx # Main layout
3├── page.tsx # Main page
4└── dashboard/
5 ├── layout.tsx # Layout with multiple slots
6 │ // layout.tsx defines slots {children, @stats, @notifications}
7 ├── page.tsx # Default content for the main slot
8 ├── @stats/
9 │ ├── page.tsx # Content for the @stats slot
10 │ └── default.tsx # Required in Next.js 16 (e.g. returns null)
11 └── @notifications/
12 ├── page.tsx # Content for the @notifications slot
13 └── default.tsx # Required in Next.js 16 (e.g. returns null)Dans Next.js 16, chaque slot doit avoir un fichier default.tsx (par exemple qui retourne null ou appelle notFound()), sinon next build échoue.
1// app/dashboard/layout.tsx
2export default function DashboardLayout({
3 children,
4 stats,
5 notifications,
6}: {
7 children: React.ReactNode;
8 stats: React.ReactNode;
9 notifications: React.ReactNode;
10}) {
11 return (
12 <div className="dashboard-grid">
13 <main>{children}</main>
14 <aside className="stats-panel">{stats}</aside>
15 <section className="notifications-panel">{notifications}</section>
16 </div>
17 );
18}Les routes parallèles sont comme les dimensions parallèles de Quantum Metropolis - différentes réalités accessibles simultanément.
3. Intercepting Routes (routes d'interception)
Elles permettent d'« intercepter » une route et de l'afficher différemment, ce qui est idéal pour les modales qui préservent le contexte de navigation. Elles sont indiquées par le nom du segment précédé du signe « (.) » : (.)name, (..)name ou (...)name.
1app/
2├── layout.tsx
3├── page.tsx # Route: /
4└── dashboard/
5 ├── layout.tsx
6 ├── page.tsx # Route: /dashboard
7 └── projects/
8 ├── layout.tsx # Renders {children} and {modal}
9 ├── page.tsx # Route: /dashboard/projects
10 ├── [id]/
11 │ └── page.tsx # Route: /dashboard/projects/:id
12 ├── create/
13 │ └── page.tsx # Route: /dashboard/projects/create (full page)
14 └── @modal/
15 ├── default.tsx # Returns null when the modal is closed
16 └── (.)create/
17 └── page.tsx # Modal over the list when opened via a linkQuand tu suis un lien depuis la liste, Next.js affiche la page interceptée dans le slot @modal au-dessus de la liste ; après un rafraîchissement ou en ouvrant directement l'adresse, il affiche la page complète create/page.tsx.
Les routes d'interception sont comme les raccourcis quantiques de Quantum Metropolis - elles permettent un accès rapide aux ressources sans changer de contexte.
Organisation du code dans Next.js 16
Outre la structure de routage, Next.js 16 suggère des façons précises d'organiser le code. C'est comme la planification des quartiers à Quantum Metropolis - une bonne organisation augmente l'efficacité et la lisibilité.
Composants et ressources partagés
Les composants utilisés à plusieurs endroits doivent être organisés de manière cohérente. Voici la structure recommandée :
1src/
2├── app/ # Application with App Router
3│ ├── layout.tsx
4│ └── page.tsx
5├── components/ # Shared components
6│ ├── ui/ # Basic UI components
7│ │ ├── Button.tsx
8│ │ └── Card.tsx
9│ └── features/ # Feature-specific components
10│ ├── dashboard/
11│ └── auth/
12├── lib/ # Shared functions and classes
13│ ├── api/
14│ └── utils/
15├── hooks/ # Custom React hooks
16│ ├── useAuth.ts
17│ └── useLocalStorage.ts
18└── styles/ # Global styles
19 └── globals.cssCo-location vs. centralisation
Next.js 16 et l'App Router favorisent une approche de « co-location », où les fichiers liés à une route spécifique sont placés à proximité les uns des autres. C'est comme les micro-quartiers de Quantum Metropolis - tout ce dont tu as besoin est à portée de main.
1app/
2└── dashboard/
3 ├── page.tsx
4 ├── loading.tsx # Loading for this route
5 ├── error.tsx # Error handling for this route
6 ├── layout.tsx # Layout for this route
7 ├── actions.ts # Server Actions for this route
8 ├── components/ # Components specific to this route
9 │ ├── StatusCard.tsx
10 │ └── DashboardNav.tsx
11 └── styles/ # Styles specific to this route
12 └── dashboard.module.cssComparaison de l'App Router et du Pages Router
Maintenant que nous avons exploré les deux systèmes de routage, comparons-les - tout comme les ingénieurs de Quantum Metropolis pourraient comparer le transport classique et la téléportation quantique.
Rendu
Pages Router :
- Par défaut, chaque page est pré-rendue en HTML (optimisation statique automatique), puis hydratée dans le navigateur
- SSR et SSG disponibles via getServerSideProps et getStaticProps
- Modèles de données relativement simples
App Router :
- Server Components par défaut
- Choix entre Server et Client Components
- Modèle de flux de données plus avancé
- Rendu en streaming
Dans le Pages Router, une page obtient ses données grâce à une fonction exportée à côté du composant, par exemple getStaticProps, que Next.js appelle une seule fois, pendant le build :
1// pages/posts.js (Pages Router)
2export async function getStaticProps() {
3 const posts = await getPosts();
4 return { props: { posts } };
5}La fonction getServerSideProps a la même forme, mais Next.js l'appelle à chaque requête.
État de chargement
Pages Router :
- Gestion manuelle de l'état de chargement
- Utilise souvent des bibliothèques externes
App Router :
- Composants loading.tsx intégrés
- Intégration avec React Suspense
- Indicateurs de chargement automatiques
Gestion des erreurs
Pages Router :
- Gestion manuelle des erreurs
- Composant général pour les erreurs 500
App Router :
- Composants error.tsx avec gestion granulaire des erreurs
- Intégration avec React Error Boundary
- Possibilité de récupérer / réessayer après une erreur
Layouts
Pages Router :
- Création manuelle des layouts avec le composant _app.js
- Un seul layout pour toute l'application
- Les layouts imbriqués demandent du travail supplémentaire
App Router :
- Système de layouts intégré via layout.tsx
- Possibilité de créer des layouts imbriqués
- Le partage de layout est simple et intuitif
Quand utiliser quel système de routage ?
Choisir entre l'App Router et le Pages Router ressemble au choix entre la téléportation quantique et le transport traditionnel à Quantum Metropolis - cela dépend des besoins spécifiques.
Utilise l'App Router quand :
- Tu crées un nouveau projet de zéro
- Tu veux utiliser les dernières fonctionnalités de React et Next.js
- Tu as besoin de capacités avancées de layout et d'organisation
- Tu tiens à de meilleures performances et au rendu en streaming
- Tu veux utiliser les React Server Components
Utilise le Pages Router quand :
- Tu as un projet existant basé sur le Pages Router
- Tu as besoin d'un modèle mental plus simple
- Tu utilises des bibliothèques qui ne sont pas encore compatibles avec l'App Router
- Tu veux utiliser des patterns et des solutions tout prêts
Migration du Pages Router vers l'App Router
Si tu as un projet existant utilisant le Pages Router, tu peux migrer progressivement vers l'App Router. C'est comme moderniser les quartiers de Quantum Metropolis - tu n'as pas à tout reconstruire d'un coup.
Next.js 16 permet aux deux systèmes de coexister. Tu peux commencer à utiliser app/ pour les nouvelles fonctionnalités tout en gardant les pages existantes dans pages/.
1.
2├── app/ # New features using App Router
3│ ├── new-feature/
4│ │ └── page.tsx # /new-feature
5│ └── layout.tsx
6└── pages/ # Existing pages using Pages Router
7 ├── index.js # /
8 └── about.js # /aboutNotes importantes sur la migration :
- Les routes dans
app/ont la priorité sur les routes danspages/, mais une même adresse ne peut pas exister dans les deux dossiers : Next.js signale une erreur pendant le build - Les deux structures utilisent la même configuration Next.js
- Tu peux déplacer progressivement les pages de
pages/versapp/
Bonnes pratiques d'organisation des fichiers
Quel que soit le système de routage choisi, il vaut la peine de suivre certaines bonnes pratiques :
Structure orientée fonctionnalité : organise les composants et le code autour des fonctionnalités métier, plutôt que par types techniques.
1src/ 2├── features/ 3│ ├── auth/ 4│ │ ├── components/ 5│ │ ├── hooks/ 6│ │ └── utils/ 7│ └── dashboard/ 8│ ├── components/ 9│ ├── hooks/ 10│ └── utils/Approche modulaire : traite chaque fonctionnalité comme un module isolé avec une API clairement définie.
Conventions de nommage cohérentes : établis des conventions et respecte-les tout au long du projet.
- Fichiers de composants : PascalCase (Button.tsx)
- Hooks : camelCase avec le préfixe « use » (useAuth.ts)
- Fonctions utilitaires : camelCase (formatDate.ts)
Imports relatifs vs. absolus : utilise les alias d'import (
@/) pour une meilleure lisibilité et un déplacement de fichiers plus facile.Co-location des tests : place les tests à proximité des composants testés.
1src/ 2├── components/ 3│ ├── Button.tsx 4│ └── Button.test.tsx
Résumé
La structure des répertoires et des fichiers dans Next.js 16 est comme l'architecture de Quantum Metropolis - avec une bonne planification, elle peut être à la fois élégante et fonctionnelle. L'App Router introduit un modèle d'organisation d'application plus avancé mais aussi plus flexible, tandis que le Pages Router offre une approche plus simple et plus directe.
Le choix entre les deux dépend des besoins spécifiques du projet, mais pour les nouveaux projets, il est recommandé d'utiliser l'App Router afin de profiter des dernières fonctionnalités et optimisations. Souviens-toi qu'une bonne organisation du projet est la clé d'une maintenance et d'une extensibilité faciles à l'avenir.
Dans la prochaine leçon, nous nous plongerons dans le système de composants de Next.js 16, en particulier les différences entre les Client Components et les Server Components, qui constituent une partie fondamentale de l'App Router.
Code de cette leçon : App.tsx
1// Props et State - Metropolis Quantum
2import React, { useState } from 'react';
3
4console.log("Props et State dans React");
5console.log("Gestion des données à Quantum City\n");
6
7// ==========================================
8// 1. PROPS - passer des données
9// ==========================================
10console.log("=== 1. PROPS - propriétés ===");
11
12interface UserCardProps {
13 name: string;
14 role: string;
15 level: number;
16 avatar: string;
17}
18
19const UserCard: React.FC<UserCardProps> = ({ name, role, level, avatar }) => {
20 return (
21 <div style={{
22 background: 'rgba(255, 255, 255, 0.1)',
23 padding: '20px',
24 borderRadius: '12px',
25 border: '2px solid #64ffda',
26 display: 'flex',
27 alignItems: 'center',
28 gap: '15px',
29 marginBottom: '15px'
30 }}>
31 <div style={{ fontSize: '3rem' }}>{avatar}</div>
32 <div>
33 <h3 style={{ color: '#64ffda', margin: '0 0 5px 0' }}>{name}</h3>
34 <p style={{ margin: '5px 0', color: '#b0bec5' }}>Rôle : {role}</p>
35 <p style={{ margin: '5px 0', color: '#ff9800' }}>Niveau : {level}</p>
36 </div>
37 </div>
38 );
39};
40
41// ==========================================
42// 2. STATE - état du composant
43// ==========================================
44console.log("\n=== 2. STATE - Hook useState ===");
45
46function QuantumCounter() {
47 // useState renvoie [valeur, fonction pour changer la valeur]
48 const [energy, setEnergy] = useState<number>(50);
49 const [isCharging, setIsCharging] = useState<boolean>(false);
50
51 const charge = () => {
52 if (energy < 100) {
53 setEnergy(energy + 10);
54 setIsCharging(true);
55 setTimeout(() => setIsCharging(false), 300);
56 console.log(`Chargement de l'énergie : ${energy + 10}%`);
57 }
58 };
59
60 const discharge = () => {
61 if (energy > 0) {
62 setEnergy(energy - 10);
63 console.log(`Déchargement de l'énergie : ${energy - 10}%`);
64 }
65 };
66
67 const reset = () => {
68 setEnergy(50);
69 console.log("Énergie réinitialisée à 50%");
70 };
71
72 const getEnergyColor = () => {
73 if (energy > 70) return '#4caf50';
74 if (energy > 30) return '#ff9800';
75 return '#f44336';
76 };
77
78 return (
79 <div style={{
80 background: 'rgba(124, 77, 255, 0.2)',
81 padding: '20px',
82 borderRadius: '12px',
83 border: '2px solid #7c4dff'
84 }}>
85 <h3 style={{ color: '#7c4dff' }}>Générateur d'énergie quantique</h3>
86
87 <div style={{
88 background: 'rgba(0, 0, 0, 0.5)',
89 padding: '15px',
90 borderRadius: '8px',
91 marginBottom: '15px'
92 }}>
93 <div style={{
94 fontSize: '2rem',
95 textAlign: 'center',
96 color: getEnergyColor(),
97 marginBottom: '10px'
98 }}>
99 {energy}%
100 </div>
101 <div style={{
102 width: '100%',
103 height: '20px',
104 background: 'rgba(255, 255, 255, 0.1)',
105 borderRadius: '10px',
106 overflow: 'hidden'
107 }}>
108 <div style={{
109 width: `${energy}%`,
110 height: '100%',
111 background: `linear-gradient(90deg, ${getEnergyColor()}, #64ffda)`,
112 transition: 'all 0.3s ease',
113 transform: isCharging ? 'scale(1.05)' : 'scale(1)'
114 }}></div>
115 </div>
116 </div>
117
118 <div style={{ display: 'flex', gap: '10px', justifyContent: 'center' }}>
119 <button
120 onClick={charge}
121 disabled={energy >= 100}
122 style={{
123 background: energy >= 100 ? '#555' : 'linear-gradient(45deg, #4caf50, #8bc34a)',
124 color: 'white',
125 border: 'none',
126 padding: '10px 20px',
127 borderRadius: '6px',
128 cursor: energy >= 100 ? 'not-allowed' : 'pointer',
129 fontWeight: 'bold'
130 }}
131 >
132 Charger
133 </button>
134
135 <button
136 onClick={discharge}
137 disabled={energy <= 0}
138 style={{
139 background: energy <= 0 ? '#555' : 'linear-gradient(45deg, #f44336, #e91e63)',
140 color: 'white',
141 border: 'none',
142 padding: '10px 20px',
143 borderRadius: '6px',
144 cursor: energy <= 0 ? 'not-allowed' : 'pointer',
145 fontWeight: 'bold'
146 }}
147 >
148 Décharger
149 </button>
150
151 <button
152 onClick={reset}
153 style={{
154 background: 'linear-gradient(45deg, #607d8b, #90a4ae)',
155 color: 'white',
156 border: 'none',
157 padding: '10px 20px',
158 borderRadius: '6px',
159 cursor: 'pointer',
160 fontWeight: 'bold'
161 }}
162 >
163 Réinitialiser
164 </button>
165 </div>
166 </div>
167 );
168}
169
170// ==========================================
171// 3. Props + State ensemble
172// ==========================================
173console.log("\n=== 3. Props + State combinés ===");
174
175interface SystemStatusProps {
176 systemName: string;
177 initialStatus: 'online' | 'offline' | 'maintenance';
178}
179
180const SystemStatus: React.FC<SystemStatusProps> = ({ systemName, initialStatus }) => {
181 const [status, setStatus] = useState(initialStatus);
182 const [uptime, setUptime] = useState(0);
183
184 const toggleStatus = () => {
185 const statuses: Array<'online' | 'offline' | 'maintenance'> = ['online', 'offline', 'maintenance'];
186 const currentIndex = statuses.indexOf(status);
187 const nextStatus = statuses[(currentIndex + 1) % statuses.length];
188 setStatus(nextStatus);
189 setUptime(0);
190 console.log(`Statut de ${systemName} changé en : ${nextStatus}`);
191 };
192
193 const getStatusColor = () => {
194 switch(status) {
195 case 'online': return '#4caf50';
196 case 'offline': return '#f44336';
197 case 'maintenance': return '#ff9800';
198 }
199 };
200
201 return (
202 <div style={{
203 background: 'rgba(255, 255, 255, 0.1)',
204 padding: '15px',
205 borderRadius: '10px',
206 border: `2px solid ${getStatusColor()}`,
207 marginBottom: '15px'
208 }}>
209 <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
210 <div>
211 <h4 style={{ margin: '0 0 10px 0', color: '#64ffda' }}>{systemName}</h4>
212 <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
213 <div style={{
214 width: '12px',
215 height: '12px',
216 borderRadius: '50%',
217 background: getStatusColor(),
218 boxShadow: `0 0 10px ${getStatusColor()}`
219 }}></div>
220 <span style={{ color: getStatusColor(), textTransform: 'uppercase', fontWeight: 'bold' }}>
221 {status}
222 </span>
223 </div>
224 </div>
225 <button
226 onClick={toggleStatus}
227 style={{
228 background: 'linear-gradient(45deg, #2196f3, #21cbf3)',
229 color: 'white',
230 border: 'none',
231 padding: '8px 16px',
232 borderRadius: '6px',
233 cursor: 'pointer',
234 fontWeight: 'bold'
235 }}
236 >
237 Changer le statut
238 </button>
239 </div>
240 </div>
241 );
242};
243
244// ==========================================
245// App principale
246// ==========================================
247function App() {
248 const citizens = [
249 { name: 'Alex Quantum', role: 'Architecte en chef', level: 42, avatar: '' },
250 { name: 'Nova Star', role: 'Data Scientist', level: 38, avatar: '' },
251 { name: 'Cypher Neo', role: 'Expert en sécurité', level: 45, avatar: '' }
252 ];
253
254 return (
255 <div style={{
256 padding: '20px',
257 background: 'linear-gradient(135deg, #0f0f23 0%, #1a1a2e 100%)',
258 minHeight: '100vh',
259 color: 'white'
260 }}>
261 <h1 style={{ textAlign: 'center', color: '#64ffda' }}>Panneau de contrôle de la Metropolis</h1>
262
263 <div style={{ marginTop: '30px' }}>
264 <h2 style={{ color: '#7c4dff' }}>Citoyens (démo Props)</h2>
265 {citizens.map((citizen, index) => (
266 <UserCard
267 key={index}
268 name={citizen.name}
269 role={citizen.role}
270 level={citizen.level}
271 avatar={citizen.avatar}
272 />
273 ))}
274 </div>
275
276 <div style={{ marginTop: '30px' }}>
277 <h2 style={{ color: '#7c4dff' }}>Système d'énergie (démo State)</h2>
278 <QuantumCounter />
279 </div>
280
281 <div style={{ marginTop: '30px' }}>
282 <h2 style={{ color: '#7c4dff' }}>État des systèmes (Props + State)</h2>
283 <SystemStatus systemName="Quantum Core" initialStatus="online" />
284 <SystemStatus systemName="Neural Network" initialStatus="maintenance" />
285 <SystemStatus systemName="Transport Grid" initialStatus="offline" />
286 </div>
287
288 <div style={{
289 marginTop: '30px',
290 background: 'rgba(100, 255, 218, 0.1)',
291 padding: '20px',
292 borderRadius: '10px',
293 borderLeft: '4px solid #64ffda'
294 }}>
295 <h3>Props vs State :</h3>
296 <ul style={{ lineHeight: '1.8' }}>
297 <li><strong>Props</strong> : transmises par le parent, en lecture seule, comme des paramètres de fonction</li>
298 <li><strong>State</strong> : état interne du composant, modifiable, provoque un re-rendu du composant</li>
299 <li><strong>Props + State</strong> : le plus souvent utilisés ensemble pour une UI dynamique</li>
300 </ul>
301 </div>
302 </div>
303 );
304}
305
306export default App;Tu as repéré une erreur dans cette leçon ?
Teste tes connaissances
Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.
1. Que signifie la « programmation déclarative » dans le contexte de React ?
2. Les composants React peuvent être :
Tâches pratiques dans le jeu
- Tri horizontal
Ordonne le chemin vers une page d'article dynamique dans Next.js
- Éditeur de code
Crée le composant de page About pour le fichier pages/about.js (export default function About). La page doit afficher un titre <h1> ou <h2> avec le nom de l'entreprise et un paragraphe <p> avec des informations sur l'entreprise.