Cours JavaScript et React · Module 6: React Router

Les paramètres d'URL dans la navigation cosmique

13 min de lecture
Dans cette leçon10

Lors des voyages interplanétaires, les coordonnées et les identifiants des corps célestes sont essentiels à la navigation. De la même manière, dans React Router, les paramètres d'URL permettent de diriger précisément l'utilisateur vers des ressources spécifiques de l'application. Dans ce module, nous apprendrons à utiliser, lire et manipuler les paramètres d'URL dans nos applications spatiales.

Que sont les paramètres d'URL ?

Les paramètres d'URL sont des parties variables d'une adresse URL qui peuvent contenir des valeurs dynamiques. Dans React Router, ils existent sous deux formes principales :

  1. Paramètres de chemin - intégrés dans la structure de l'URL (par ex. /planets/:planetId)
  2. Paramètres de requête - ajoutés après le point d'interrogation (par ex. /planets?type=rocky&inhabited=true)

Les paramètres de chemin

Les paramètres de chemin font partie de la structure même de l'URL et sont définis par un deux-points (:) dans la définition de la route.

Définir des routes avec des paramètres de chemin

1import { Routes, Route } from 'react-router-dom';
2
3function AppRoutes() {
4  return (
5    <Routes>
6      <Route path="/" element={<Dashboard />} />
7      <Route path="/planets/:planetId" element={<PlanetDetails />} />
8      <Route path="/missions/:year/:missionId" element={<MissionDetails />} />
9    </Routes>
10  );
11}

Dans l'exemple ci-dessus :

  • :planetId est un paramètre dans le chemin /planets/:planetId
  • :year et :missionId sont des paramètres dans le chemin /missions/:year/:missionId

Ces chemins correspondront à des URL telles que :

  • /planets/mars
  • /planets/jupiter
  • /missions/2150/mars-expedition

Accéder aux paramètres de chemin avec useParams

Pour lire les valeurs des paramètres de chemin dans un composant, on utilise le hook useParams :

1import { useParams } from 'react-router-dom';
2
3function PlanetDetails() {
4  const { planetId } = useParams();
5
6  return (
7    <div className="planet-details">
8      <h1>Détails de la planète : {planetId}</h1>
9      {/* Reste du composant utilisant la valeur de planetId */}
10    </div>
11  );
12}

Dans un composant plus complexe, on peut utiliser le paramètre pour récupérer des données :

1import { useParams } from 'react-router-dom';
2import { useState, useEffect } from 'react';
3
4function PlanetDetails() {
5  const { planetId } = useParams();
6  const [planetData, setPlanetData] = useState(null);
7  const [loading, setLoading] = useState(true);
8  const [error, setError] = useState(null);
9
10  useEffect(() => {
11    // Réinitialiser l'état lorsque le paramètre change
12    setLoading(true);
13    setError(null);
14
15    // Récupérer les données de la planète spécifique
16    fetch(`https://api.space-explorer.com/planets/${planetId}`)
17      .then(response => {
18        if (!response.ok) {
19          throw new Error('Impossible de récupérer les données de la planète');
20        }
21        return response.json();
22      })
23      .then(data => {
24        setPlanetData(data);
25        setLoading(false);
26      })
27      .catch(err => {
28        setError(err.message);
29        setLoading(false);
30      });
31  }, [planetId]); // Relancer l'effet quand planetId change
32
33  if (loading) return <div>Chargement des données de la planète...</div>;
34  if (error) return <div>Erreur : {error}</div>;
35  if (!planetData) return <div>Planète introuvable</div>;
36
37  return (
38    <div className="planet-details">
39      <h1>{planetData.name}</h1>
40      <div className="planet-info">
41        <p>Diamètre : {planetData.diameter} km</p>
42        <p>Distance du Soleil : {planetData.distanceFromSun} millions de km</p>
43        <p>Température de surface : {planetData.surfaceTemperature}°C</p>
44        <p>Type : {planetData.type}</p>
45      </div>
46      {/* Plus d'informations sur la planète */}
47    </div>
48  );
49}

Paramètres de chemin optionnels

Le journal de mission a deux vues : la liste de toutes les missions à l'adresse /missions et les missions d'une seule année, par ex. /missions/2150. L'année est donc tantôt présente dans l'adresse, tantôt absente. Depuis la version 6.5 (décembre 2022, et de la même façon en v7 et v8), React Router te permet de marquer un tel segment comme optionnel : il suffit d'ajouter un point d'interrogation à sa fin.

1<Routes>
2  <Route path="/missions/:year?" element={<MissionsList />} />
3</Routes>

Une seule route gère maintenant les deux adresses : /missions et /missions/2150. Le point d'interrogation ne concerne que le segment auquel il est accolé, c'est pourquoi l'adresse /missions/2150/06 ne correspond pas à cette route. Le motif /missions/:year?/:month? de la leçon sur la configuration du routage fonctionne de la même façon : chacun des deux segments est optionnel séparément.

Tu lis le paramètre comme avant, avec le hook useParams. La seule nouveauté : pour une adresse sans année, year vaut undefined, donc le composant doit gérer les deux cas :

1import { useParams } from 'react-router-dom';
2
3function MissionsList() {
4  const { year } = useParams();
5
6  return <h2>{year ? `Missions de ${year}` : 'Toutes les missions'}</h2>;
7}

Le composant ne sait pas pour quelle adresse il a été rendu, et il n'en a pas besoin. Il reçoit year ou undefined et choisit le titre en fonction de cela. Un segment statique, c'est-à-dire un simple mot du chemin et non un paramètre, peut lui aussi être optionnel :

1<Route path="/crew/:memberId/edit?" element={<CrewMember />} />

Cette route correspond aussi bien à /crew/ra qu'à /crew/ra/edit, et rend le même composant CrewMember dans les deux cas.

Dans les versions 6.0 à 6.4, le point d'interrogation ne fonctionnait pas, il fallait donc définir deux routes distinctes avec le même élément. Cette écriture reste valide et tu la croiseras dans des projets plus anciens :

1<Routes>
2  <Route path="/missions" element={<MissionsList />} />
3  <Route path="/missions/:year" element={<MissionsList />} />
4</Routes>

La troisième voie, ce sont les paramètres de requête, optionnels par nature. Je te conseille une règle simple : choisis un segment optionnel quand la valeur construit la hiérarchie de l'adresse, comme l'année dans le journal de mission, et des paramètres de requête quand il s'agit de filtres combinables librement. Tu découvriras les paramètres de requête dans la section suivante.

Les paramètres de requête

Les paramètres de requête sont des paires clé-valeur ajoutées après le point d'interrogation (?) dans l'URL. Exemple : /search?query=mars&category=planets

Accéder aux paramètres de requête avec useSearchParams

Le hook useSearchParams permet de lire et de manipuler les paramètres de requête :

1import { useSearchParams } from 'react-router-dom';
2
3function PlanetSearch() {
4  // searchParams est un objet URLSearchParams
5  // setSearchParams est une fonction pour mettre à jour les paramètres
6  const [searchParams, setSearchParams] = useSearchParams();
7
8  // Lecture des valeurs des paramètres
9  const query = searchParams.get('query') || '';
10  const type = searchParams.get('type') || 'all';
11
12  // Fonction gérant la recherche
13  const handleSearch = (e) => {
14    e.preventDefault();
15    const formData = new FormData(e.target);
16    const newQuery = formData.get('searchQuery');
17    const newType = formData.get('planetType');
18
19    // Mettre à jour les paramètres de requête
20    setSearchParams({ query: newQuery, type: newType });
21  };
22
23  return (
24    <div className="planet-search">
25      <h1>Moteur de recherche de planètes</h1>
26
27      <form onSubmit={handleSearch}>
28        <input
29          name="searchQuery"
30          defaultValue={query}
31          placeholder="Saisis le nom de la planète..."
32        />
33
34        <select name="planetType" defaultValue={type}>
35          <option value="all">Tous les types</option>
36          <option value="rocky">Rocheuses</option>
37          <option value="gas-giant">Géantes gazeuses</option>
38          <option value="ice-giant">Géantes de glace</option>
39        </select>
40
41        <button type="submit">Rechercher</button>
42      </form>
43
44      <div className="search-results">
45        {/* Résultats de recherche selon query et type */}
46        <p>Phrase de recherche : {query || '(aucune)'}</p>
47        <p>Type de planète : {type}</p>
48      </div>
49    </div>
50  );
51}

Manipuler les paramètres de requête

Nous pouvons manipuler les paramètres de requête de différentes manières :

1// Définir de nouveaux paramètres (remplace tous les paramètres existants)
2setSearchParams({ query: 'mars', type: 'rocky' });
3
4// Ajouter ou mettre à jour un paramètre sans supprimer les existants
5setSearchParams(params => {
6  params.set('query', 'mars');
7  return params;
8});
9
10// Supprimer un paramètre
11setSearchParams(params => {
12  params.delete('type');
13  return params;
14});
15
16// Vérifier si un paramètre existe
17const hasType = searchParams.has('type');
18
19// Obtenir toutes les valeurs d'un paramètre (s'il apparaît plusieurs fois)
20const allCategories = searchParams.getAll('category');

Paramètres de requête vs. paramètres de chemin - Quand utiliser lesquels ?

Paramètres de chemin :

  • Pour identifier la ressource principale (par ex. /planets/mars)
  • Lorsque le paramètre est obligatoire
  • Lorsque la structure de l'URL doit refléter la hiérarchie des ressources
  • Exemples : ID de planète, année de mission, nom de constellation

Paramètres de requête :

  • Pour le filtrage, le tri, la pagination
  • Pour les paramètres optionnels
  • Lorsqu'il existe de nombreuses combinaisons de paramètres
  • Exemples : critères de recherche, page de résultats, limites, filtres

Combiner les paramètres de chemin et de requête

Nous pouvons combiner les deux types de paramètres pour une plus grande flexibilité :

1// URL : /planets/mars?tab=geology&unit=metric
2
3import { useParams, useSearchParams } from 'react-router-dom';
4
5function PlanetDetails() {
6  const { planetId } = useParams();
7  const [searchParams] = useSearchParams();
8
9  const activeTab = searchParams.get('tab') || 'overview';
10  const unit = searchParams.get('unit') || 'metric';
11
12  return (
13    <div>
14      <h1>Planète : {planetId}</h1>
15
16      <div className="tabs">
17        <TabLink to={`/planets/${planetId}?tab=overview&unit=${unit}`}
18          active={activeTab === 'overview'}>
19          Vue d'ensemble
20        </TabLink>
21        <TabLink to={`/planets/${planetId}?tab=geology&unit=${unit}`}
22          active={activeTab === 'geology'}>
23          Géologie
24        </TabLink>
25        <TabLink to={`/planets/${planetId}?tab=atmosphere&unit=${unit}`}
26          active={activeTab === 'atmosphere'}>
27          Atmosphère
28        </TabLink>
29      </div>
30
31      <div className="unit-switcher">
32        <UnitToggle
33          metric={unit === 'metric'}
34          onChange={(isMetric) => {
35            const newUnit = isMetric ? 'metric' : 'imperial';
36            // Mettre à jour uniquement le paramètre unit, préserver tab
37            searchParams.set('unit', newUnit);
38            setSearchParams(searchParams);
39          }}
40        />
41      </div>
42
43      {/* Contenu selon activeTab et unit */}
44    </div>
45  );
46}

createSearchParams - Simplifier la création de paramètres de requête

La fonction createSearchParams aide à créer des paramètres de requête à partir d'objets JavaScript :

1import { createSearchParams, useNavigate } from 'react-router-dom';
2
3function PlanetFilterPanel() {
4  const navigate = useNavigate();
5
6  const applyFilters = (filters) => {
7    // Convertir l'objet de filtres en paramètres d'URL
8    const params = createSearchParams({
9      type: filters.type,
10      minSize: filters.minSize,
11      hasWater: filters.hasWater ? 'true' : undefined,
12      sortBy: filters.sortBy
13    });
14
15    // Naviguer avec les paramètres
16    navigate({
17      pathname: '/planets',
18      search: `?${params}`
19    });
20  };
21
22  return (
23    <form onSubmit={(e) => {
24      e.preventDefault();
25      const form = e.target;
26      applyFilters({
27        type: form.type.value,
28        minSize: form.minSize.value,
29        hasWater: form.hasWater.checked,
30        sortBy: form.sortBy.value
31      });
32    }}>
33      {/* Formulaire de filtres */}
34      <button type="submit">Appliquer les filtres</button>
35    </form>
36  );
37}

Générer des liens avec des paramètres

Pour créer des liens avec des paramètres, nous pouvons utiliser :

Pour les paramètres de chemin :

1// Simple concaténation de chaînes
2<Link to={`/planets/${planetId}`}>
3  Détails de la planète {planetName}
4</Link>
5
6// Utilisation d'un objet (plus flexible)
7<Link to={{
8  pathname: `/planets/${planetId}`,
9}}>
10  Détails de la planète {planetName}
11</Link>

Pour les paramètres de requête :

1import { Link, createSearchParams } from 'react-router-dom';
2
3// Utilisation de createSearchParams
4<Link to={{
5  pathname: '/planets',
6  search: `?${createSearchParams({
7    type: 'rocky',
8    inhabited: 'true'
9  })}`
10}}>
11  Planètes rocheuses habitées
12</Link>
13
14// Ou création manuelle des paramètres
15<Link to={`/planets?type=rocky&inhabited=true`}>
16  Planètes rocheuses habitées
17</Link>

Exemple complet d'application avec paramètres d'URL

Voyons maintenant un exemple complet d'application spatiale utilisant à la fois des paramètres de chemin et des paramètres de requête :

1import React, { useState, useEffect } from 'react';
2import {
3  BrowserRouter,
4  Routes,
5  Route,
6  Link,
7  useParams,
8  useSearchParams,
9  createSearchParams,
10  useNavigate
11} from 'react-router-dom';
12
13// Simulation d'API
14const planetsData = [
15  { id: 'mercury', name: 'Mercure', type: 'rocky', diameter: 4879, hasWater: false },
16  { id: 'venus', name: 'Vénus', type: 'rocky', diameter: 12104, hasWater: false },
17  { id: 'earth', name: 'Terre', type: 'rocky', diameter: 12742, hasWater: true },
18  { id: 'mars', name: 'Mars', type: 'rocky', diameter: 6779, hasWater: true },
19  { id: 'jupiter', name: 'Jupiter', type: 'gas-giant', diameter: 139820, hasWater: true },
20  { id: 'saturn', name: 'Saturne', type: 'gas-giant', diameter: 116460, hasWater: true },
21  { id: 'uranus', name: 'Uranus', type: 'ice-giant', diameter: 50724, hasWater: true },
22  { id: 'neptune', name: 'Neptune', type: 'ice-giant', diameter: 49244, hasWater: true },
23];
24
25// Composants principaux
26function PlanetsList() {
27  const [searchParams, setSearchParams] = useSearchParams();
28  const navigate = useNavigate();
29
30  // Lire les paramètres de requête
31  const type = searchParams.get('type') || 'all';
32  const hasWater = searchParams.get('hasWater');
33  const sortBy = searchParams.get('sortBy') || 'name';
34
35  // Filtrer les planètes
36  const filteredPlanets = planetsData
37    .filter(planet => type === 'all' || planet.type === type)
38    .filter(planet => hasWater === null || (hasWater === 'true' && planet.hasWater))
39    .sort((a, b) => {
40      if (sortBy === 'name') return a.name.localeCompare(b.name);
41      if (sortBy === 'diameter') return b.diameter - a.diameter;
42      return 0;
43    });
44
45  // Fonction pour mettre à jour les filtres
46  const updateFilters = (newFilters) => {
47    const params = createSearchParams({
48      ...Object.fromEntries(searchParams),
49      ...newFilters
50    });
51    setSearchParams(params);
52  };
53
54  return (
55    <div className="planets-list">
56      <h1>Catalogue des planètes</h1>
57
58      <div className="filters">
59        <label>
60          Type de planète :
61          <select
62            value={type}
63            onChange={(e) => updateFilters({ type: e.target.value })}
64          >
65            <option value="all">Toutes</option>
66            <option value="rocky">Rocheuses</option>
67            <option value="gas-giant">Géantes gazeuses</option>
68            <option value="ice-giant">Géantes de glace</option>
69          </select>
70        </label>
71
72        <label>
73          <input
74            type="checkbox"
75            checked={hasWater === 'true'}
76            onChange={(e) => updateFilters({ hasWater: e.target.checked ? 'true' : null })}
77          />
78          Avec eau uniquement
79        </label>
80
81        <label>
82          Trier par :
83          <select
84            value={sortBy}
85            onChange={(e) => updateFilters({ sortBy: e.target.value })}
86          >
87            <option value="name">Nom</option>
88            <option value="diameter">Taille</option>
89          </select>
90        </label>
91      </div>
92
93      <ul className="planets-grid">
94        {filteredPlanets.map(planet => (
95          <li key={planet.id} className={`planet ${planet.type}`}>
96            <Link to={`/planets/${planet.id}`}>
97              <h2>{planet.name}</h2>
98              <p>Type : {planet.type}</p>
99              <p>Diamètre : {planet.diameter} km</p>
100              <p>Eau : {planet.hasWater ? 'Présente' : 'Absente'}</p>
101            </Link>
102          </li>
103        ))}
104      </ul>
105
106      {filteredPlanets.length === 0 && (
107        <p>Aucune planète ne correspond aux critères.</p>
108      )}
109
110      <button onClick={() => navigate('/')}>
111        Retour au centre de contrôle
112      </button>
113    </div>
114  );
115}
116
117function PlanetDetails() {
118  const { planetId } = useParams();
119  const [searchParams, setSearchParams] = useSearchParams();
120  const navigate = useNavigate();
121
122  // Lire les paramètres de requête
123  const activeTab = searchParams.get('tab') || 'overview';
124
125  // Trouver la planète avec l'ID donné
126  const planet = planetsData.find(p => p.id === planetId);
127
128  // Si la planète est introuvable
129  if (!planet) {
130    return (
131      <div className="planet-not-found">
132        <h1>La planète n'existe pas !</h1>
133        <p>Aucune planète trouvée avec l'identifiant : {planetId}</p>
134        <button onClick={() => navigate('/planets')}>
135          Retour au catalogue des planètes
136        </button>
137      </div>
138    );
139  }
140
141  // Changer l'onglet actif
142  const changeTab = (tab) => {
143    setSearchParams({ tab });
144  };
145
146  return (
147    <div className="planet-details">
148      <h1>{planet.name}</h1>
149
150      <div className="tabs">
151        <button
152          className={activeTab === 'overview' ? 'active' : ''}
153          onClick={() => changeTab('overview')}
154        >
155          Vue d'ensemble
156        </button>
157        <button
158          className={activeTab === 'composition' ? 'active' : ''}
159          onClick={() => changeTab('composition')}
160        >
161          Composition
162        </button>
163        <button
164          className={activeTab === 'exploration' ? 'active' : ''}
165          onClick={() => changeTab('exploration')}
166        >
167          Exploration
168        </button>
169      </div>
170
171      <div className="tab-content">
172        {activeTab === 'overview' && (
173          <div>
174            <h2>Vue d'ensemble de la planète {planet.name}</h2>
175            <p>Type : {planet.type}</p>
176            <p>Diamètre : {planet.diameter} km</p>
177            <p>Eau : {planet.hasWater ? 'Présente' : 'Absente'}</p>
178          </div>
179        )}
180
181        {activeTab === 'composition' && (
182          <div>
183            <h2>Composition de la planète {planet.name}</h2>
184            <p>Les informations sur la composition de la planète apparaîtront ici...</p>
185          </div>
186        )}
187
188        {activeTab === 'exploration' && (
189          <div>
190            <h2>Exploration de la planète {planet.name}</h2>
191            <p>Les informations sur les missions d'exploration apparaîtront ici...</p>
192          </div>
193        )}
194      </div>
195
196      <Link to="/planets">Retour au catalogue des planètes</Link>
197    </div>
198  );
199}
200
201function App() {
202  return (
203    <BrowserRouter>
204      <div className="space-app">
205        <header>
206          <h1>Système de navigation cosmique</h1>
207        </header>
208
209        <main>
210          <Routes>
211            <Route path="/" element={<Dashboard />} />
212            <Route path="/planets" element={<PlanetsList />} />
213            <Route path="/planets/:planetId" element={<PlanetDetails />} />
214            <Route path="*" element={<NotFound />} />
215          </Routes>
216        </main>
217
218        <footer>
219          <p>&copy; 2150 Agence spatiale interplanétaire</p>
220        </footer>
221      </div>
222    </BrowserRouter>
223  );
224}
225
226// Autres composants
227function Dashboard() {
228  return (
229    <div className="dashboard">
230      <h1>Centre de contrôle de mission</h1>
231      <p>Bienvenue dans le système de navigation cosmique !</p>
232      <Link to="/planets">Parcourir le catalogue des planètes</Link>
233    </div>
234  );
235}
236
237function NotFound() {
238  return (
239    <div className="not-found">
240      <h1>Erreur de navigation : 404</h1>
241      <p>Perdu dans l'espace ! Cette page n'existe pas.</p>
242      <Link to="/">Retour au centre de contrôle</Link>
243    </div>
244  );
245}
246
247export default App;

Bonnes pratiques pour les paramètres d'URL

  1. Utilise des noms de paramètres lisibles - ils doivent décrire ce qu'ils représentent
  2. Choisis le type de paramètres approprié - paramètres de chemin pour les ressources principales, paramètres de requête pour les filtres
  3. Gère les paramètres manquants - fournis toujours des valeurs par défaut
  4. Valide les paramètres - vérifie que les valeurs sont correctes avant de les utiliser
  5. Préserve l'état des paramètres de requête - ne mets à jour que les paramètres qui changent
  6. Utilise les paramètres pour stocker l'état de l'interface - cela facilite le partage et l'enregistrement de l'état

Résumé

Les paramètres d'URL sont un outil puissant dans la navigation cosmique (et dans React Router). Ils permettent de :

  • Identifier des ressources spécifiques (paramètres de chemin)
  • Filtrer et trier les données (paramètres de requête)
  • Mémoriser l'état de l'interface utilisateur
  • Créer des liens partageables et ajoutables aux favoris
  • Gérer l'historique du navigateur

Grâce à eux, les utilisateurs peuvent naviguer précisément vers des emplacements spécifiques de l'application spatiale, et toi, en tant que programmeur, peux créer des interfaces interactives et conviviales.

Code de cette leçon : App.jsx
1import React from 'react';
2import { BrowserRouter, Routes, Route, Link, useParams } from 'react-router-dom';
3
4// Liste des planètes
5const planets = [
6  { id: 'mars', name: 'Mars', emoji: '', distance: '225M km' },
7  { id: 'jupiter', name: 'Jupiter', emoji: '', distance: '628M km' },
8  { id: 'saturn', name: 'Saturne', emoji: '', distance: '1.2B km' },
9  { id: 'neptune', name: 'Neptune', emoji: '', distance: '4.3B km' },
10];
11
12// Page d'accueil avec la liste des planètes
13function PlanetList() {
14  return (
15    <div className="planet-list">
16      <h1>Catalogue des planètes</h1>
17      <div className="planets-grid">
18        {planets.map(planet => (
19          <Link
20            key={planet.id}
21            to={`/planet/${planet.id}`}
22            className="planet-card"
23          >
24            <div className="planet-emoji">{planet.emoji}</div>
25            <h3>{planet.name}</h3>
26            <p>{planet.distance}</p>
27          </Link>
28        ))}
29      </div>
30    </div>
31  );
32}
33
34// Détails de la planète - en utilisant useParams
35function PlanetDetails() {
36  const { planetId } = useParams();
37  const planet = planets.find(p => p.id === planetId);
38
39  if (!planet) {
40    return (
41      <div className="not-found">
42        <h1>Planète introuvable</h1>
43        <p>Aucune planète trouvée avec l'ID : {planetId}</p>
44        <Link to="/" className="back-link">← Retour au catalogue</Link>
45      </div>
46    );
47  }
48
49  return (
50    <div className="planet-details">
51      <Link to="/" className="back-link">← Retour au catalogue</Link>
52      <div className="planet-hero">
53        <div className="planet-emoji-large">{planet.emoji}</div>
54        <h1>{planet.name}</h1>
55      </div>
56      <div className="planet-info">
57        <div className="info-item">
58          <span className="label">ID :</span>
59          <span className="value">{planet.id}</span>
60        </div>
61        <div className="info-item">
62          <span className="label">Distance de la Terre :</span>
63          <span className="value">{planet.distance}</span>
64        </div>
65        <div className="info-item">
66          <span className="label">Paramètre d'URL :</span>
67          <span className="value code">:planetId = "{planetId}"</span>
68        </div>
69      </div>
70    </div>
71  );
72}
73
74function App() {
75  return (
76    <BrowserRouter>
77      <div className="app">
78        <Routes>
79          <Route path="/" element={<PlanetList />} />
80          <Route path="/planet/:planetId" element={<PlanetDetails />} />
81        </Routes>
82      </div>
83    </BrowserRouter>
84  );
85}
86
87export 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. 1. Quelle est la différence clé entre les composants Link et NavLink ?

Tâches pratiques dans le jeu

  • Tri horizontal

    Ordonne les éléments de syntaxe d'une Route dans React Router v6 :

  • Éditeur de code

    Paramètres d'URL dynamiques

  • Tri vertical

    Ordonne la hiérarchie de routage dans une application spatiale :

Articles utiles