Kurs JavaScript i React · Moduł 6: React Router
Parametry URL w kosmicznej nawigacji
W tej lekcji10
W międzyplanetarnych podróżach, koordynaty i identyfikatory ciał niebieskich są kluczowe dla nawigacji. Podobnie w React Router, parametry URL pozwalają na precyzyjne kierowanie użytkownika do konkretnych zasobów aplikacji. W tym module poznamy, jak używać, odczytywać i manipulować parametrami URL w naszych kosmicznych aplikacjach.
Czym są parametry URL?
Parametry URL to zmienne części adresu URL, które mogą zawierać dynamiczne wartości. W React Router występują w dwóch głównych formach:
- Parametry ścieżki (path parameters) - wbudowane w strukturę URL (np.
/planets/:planetId) - Parametry zapytania (query parameters) - dodawane po znaku zapytania (np.
/planets?type=rocky&inhabited=true)
Parametry ścieżki (Path Parameters)
Parametry ścieżki są częścią samej struktury URL i definiowane są przez dwukropek (:) w definicji trasy.
Definiowanie tras z parametrami ścieżki
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}W powyższym przykładzie:
:planetIdto parametr w ścieżce/planets/:planetId:yeari:missionIdto parametry w ścieżce/missions/:year/:missionId
Te ścieżki będą pasować do URL-i takich jak:
/planets/mars/planets/jupiter/missions/2150/mars-expedition
Dostęp do parametrów ścieżki za pomocą useParams
Do odczytania wartości parametrów ścieżki w komponencie używamy hooka useParams:
1import { useParams } from 'react-router-dom';
2
3function PlanetDetails() {
4 const { planetId } = useParams();
5
6 return (
7 <div className="planet-details">
8 <h1>Szczegóły planety: {planetId}</h1>
9 {/* Reszta komponentu używająca wartości planetId */}
10 </div>
11 );
12}W bardziej złożonym komponencie możemy użyć parametru do pobrania danych:
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 // Resetujemy stan przy zmianie parametru
12 setLoading(true);
13 setError(null);
14
15 // Pobieramy dane dla konkretnej planety
16 fetch(`https://api.space-explorer.com/planets/${planetId}`)
17 .then(response => {
18 if (!response.ok) {
19 throw new Error('Nie można pobrać danych planety');
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]); // Ponowne wykonanie efektu przy zmianie planetId
32
33 if (loading) return <div>Ładowanie danych planety...</div>;
34 if (error) return <div>Błąd: {error}</div>;
35 if (!planetData) return <div>Nie znaleziono planety</div>;
36
37 return (
38 <div className="planet-details">
39 <h1>{planetData.name}</h1>
40 <div className="planet-info">
41 <p>Średnica: {planetData.diameter} km</p>
42 <p>Odległość od Słońca: {planetData.distanceFromSun} mln km</p>
43 <p>Temperatura powierzchni: {planetData.surfaceTemperature}°C</p>
44 <p>Typ: {planetData.type}</p>
45 </div>
46 {/* Więcej informacji o planecie */}
47 </div>
48 );
49}Opcjonalne parametry ścieżki
Dziennik misji ma dwa widoki: listę wszystkich misji pod adresem /missions i misje z jednego roku, np. /missions/2150. Rok raz jest w adresie, a raz go nie ma. Od wersji 6.5 (grudzień 2022, tak samo w v7 i v8) React Router pozwala oznaczyć taki segment jako opcjonalny: wystarczy dopisać znak zapytania na jego końcu.
1<Routes>
2 <Route path="/missions/:year?" element={<MissionsList />} />
3</Routes>Jedna trasa obsługuje teraz oba adresy: /missions i /missions/2150. Znak zapytania dotyczy tylko segmentu, przy którym stoi, dlatego adres /missions/2150/06 do tej trasy nie pasuje. Tak samo działa zapis /missions/:year?/:month? z lekcji o konfiguracji routingu: każdy z dwóch segmentów jest opcjonalny osobno.
Parametr odczytujesz tak jak wcześniej, hookiem useParams. Nowe jest tylko to, że przy adresie bez roku year ma wartość undefined, więc komponent musi obsłużyć oba przypadki:
1import { useParams } from 'react-router-dom';
2
3function MissionsList() {
4 const { year } = useParams();
5
6 return <h2>{year ? `Misje z roku ${year}` : 'Wszystkie misje'}</h2>;
7}Komponent nie wie, pod którym adresem go wyrenderowano, i nie musi tego wiedzieć. Dostaje year albo undefined i na tej podstawie wybiera nagłówek. Opcjonalny może być też segment statyczny, czyli zwykłe słowo w ścieżce zamiast parametru:
1<Route path="/crew/:memberId/edit?" element={<CrewMember />} />Ta trasa pasuje zarówno do /crew/ra, jak i do /crew/ra/edit, i w obu przypadkach renderuje ten sam komponent CrewMember.
W wersjach od 6.0 do 6.4 znak zapytania nie działał, więc trzeba było zdefiniować dwie osobne trasy z tym samym elementem. Ten zapis jest nadal poprawny i spotkasz go w starszych projektach:
1<Routes>
2 <Route path="/missions" element={<MissionsList />} />
3 <Route path="/missions/:year" element={<MissionsList />} />
4</Routes>Trzecia droga to parametry zapytania, które z natury są opcjonalne. Polecam prostą zasadę: segment opcjonalny wybieraj, gdy wartość buduje hierarchię adresu, jak rok w dzienniku misji, a parametry zapytania, gdy to filtry, które można dowolnie łączyć. Parametry zapytania poznasz w następnej sekcji.
Parametry zapytania (Query Parameters)
Parametry zapytania to pary klucz-wartość dodawane po znaku zapytania (?) w URL.
Przykład: /search?query=mars&category=planets
Dostęp do parametrów zapytania za pomocą useSearchParams
Hook useSearchParams pozwala na odczytanie i manipulację parametrami zapytania:
1import { useSearchParams } from 'react-router-dom';
2
3function PlanetSearch() {
4 // searchParams to obiekt URLSearchParams
5 // setSearchParams to funkcja do aktualizacji parametrów
6 const [searchParams, setSearchParams] = useSearchParams();
7
8 // Odczytanie wartości parametrów
9 const query = searchParams.get('query') || '';
10 const type = searchParams.get('type') || 'all';
11
12 // Funkcja obsługująca wyszukiwanie
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 // Aktualizacja parametrów zapytania
20 setSearchParams({ query: newQuery, type: newType });
21 };
22
23 return (
24 <div className="planet-search">
25 <h1>Wyszukiwarka planet</h1>
26
27 <form onSubmit={handleSearch}>
28 <input
29 name="searchQuery"
30 defaultValue={query}
31 placeholder="Wpisz nazwę planety..."
32 />
33
34 <select name="planetType" defaultValue={type}>
35 <option value="all">Wszystkie typy</option>
36 <option value="rocky">Skaliste</option>
37 <option value="gas-giant">Gazowe olbrzymy</option>
38 <option value="ice-giant">Lodowe olbrzymy</option>
39 </select>
40
41 <button type="submit">Szukaj</button>
42 </form>
43
44 <div className="search-results">
45 {/* Wyniki wyszukiwania w zależności od query i type */}
46 <p>Szukana fraza: {query || '(brak)'}</p>
47 <p>Typ planety: {type}</p>
48 </div>
49 </div>
50 );
51}Manipulowanie parametrami zapytania
Możemy manipulować parametrami zapytania w różny sposób:
1// Ustawienie nowych parametrów (zastępuje wszystkie istniejące)
2setSearchParams({ query: 'mars', type: 'rocky' });
3
4// Dodanie lub aktualizacja parametru bez usuwania istniejących
5setSearchParams(params => {
6 params.set('query', 'mars');
7 return params;
8});
9
10// Usunięcie parametru
11setSearchParams(params => {
12 params.delete('type');
13 return params;
14});
15
16// Sprawdzenie, czy parametr istnieje
17const hasType = searchParams.has('type');
18
19// Pobranie wszystkich wartości dla parametru (jeśli występuje wielokrotnie)
20const allCategories = searchParams.getAll('category');Parametry zapytania vs. parametry ścieżki - kiedy używać których?
Parametry ścieżki:
- Do identyfikacji głównego zasobu (np.
/planets/mars) - Gdy parametr jest obowiązkowy
- Gdy struktura URL powinna odzwierciedlać hierarchię zasobów
- Przykłady: ID planety, rok misji, nazwa gwiazdozbioru
Parametry zapytania:
- Do filtrowania, sortowania, paginacji
- Dla parametrów opcjonalnych
- Gdy mamy wiele kombinacji parametrów
- Przykłady: kryteria wyszukiwania, strona wyników, limity, filtry
Łączenie parametrów ścieżki i zapytania
Możemy łączyć oba rodzaje parametrów dla większej elastyczności:
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>Planeta: {planetId}</h1>
15
16 <div className="tabs">
17 <TabLink to={`/planets/${planetId}?tab=overview&unit=${unit}`}
18 active={activeTab === 'overview'}>
19 Przegląd
20 </TabLink>
21 <TabLink to={`/planets/${planetId}?tab=geology&unit=${unit}`}
22 active={activeTab === 'geology'}>
23 Geologia
24 </TabLink>
25 <TabLink to={`/planets/${planetId}?tab=atmosphere&unit=${unit}`}
26 active={activeTab === 'atmosphere'}>
27 Atmosfera
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 // Aktualizacja tylko parametru unit, zachowanie tab
37 searchParams.set('unit', newUnit);
38 setSearchParams(searchParams);
39 }}
40 />
41 </div>
42
43 {/* Zawartość zależna od activeTab i unit */}
44 </div>
45 );
46}createSearchParams - ułatwienie tworzenia parametrów zapytania
Funkcja createSearchParams pomaga w tworzeniu parametrów zapytania z obiektów JavaScript:
1import { createSearchParams, useNavigate } from 'react-router-dom';
2
3function PlanetFilterPanel() {
4 const navigate = useNavigate();
5
6 const applyFilters = (filters) => {
7 // Konwersja obiektu filtrów na parametry 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 // Nawigacja z parametrami
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 {/* Formularz filtrowania */}
34 <button type="submit">Zastosuj filtry</button>
35 </form>
36 );
37}Generowanie linków z parametrami
Tworząc linki z parametrami, możemy używać:
Dla parametrów ścieżki:
1// Proste łączenie ciągów
2<Link to={`/planets/${planetId}`}>
3 Szczegóły planety {planetName}
4</Link>
5
6// Użycie obiektu (bardziej elastyczne)
7<Link to={{
8 pathname: `/planets/${planetId}`,
9}}>
10 Szczegóły planety {planetName}
11</Link>Dla parametrów zapytania:
1import { Link, createSearchParams } from 'react-router-dom';
2
3// Z użyciem createSearchParams
4<Link to={{
5 pathname: '/planets',
6 search: `?${createSearchParams({
7 type: 'rocky',
8 inhabited: 'true'
9 })}`
10}}>
11 Zamieszkane planety skaliste
12</Link>
13
14// Lub ręczne tworzenie parametrów
15<Link to={`/planets?type=rocky&inhabited=true`}>
16 Zamieszkane planety skaliste
17</Link>Pełny przykład aplikacji z parametrami URL
Zobaczmy teraz kompletny przykład kosmicznej aplikacji wykorzystującej zarówno parametry ścieżki, jak i parametry zapytania:
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// Symulacja API
14const planetsData = [
15 { id: 'mercury', name: 'Merkury', type: 'rocky', diameter: 4879, hasWater: false },
16 { id: 'venus', name: 'Wenus', type: 'rocky', diameter: 12104, hasWater: false },
17 { id: 'earth', name: 'Ziemia', type: 'rocky', diameter: 12742, hasWater: true },
18 { id: 'mars', name: 'Mars', type: 'rocky', diameter: 6779, hasWater: true },
19 { id: 'jupiter', name: 'Jowisz', type: 'gas-giant', diameter: 139820, hasWater: true },
20 { id: 'saturn', name: 'Saturn', type: 'gas-giant', diameter: 116460, hasWater: true },
21 { id: 'uranus', name: 'Uran', type: 'ice-giant', diameter: 50724, hasWater: true },
22 { id: 'neptune', name: 'Neptun', type: 'ice-giant', diameter: 49244, hasWater: true },
23];
24
25// Komponenty główne
26function PlanetsList() {
27 const [searchParams, setSearchParams] = useSearchParams();
28 const navigate = useNavigate();
29
30 // Odczytanie parametrów zapytania
31 const type = searchParams.get('type') || 'all';
32 const hasWater = searchParams.get('hasWater');
33 const sortBy = searchParams.get('sortBy') || 'name';
34
35 // Filtrowanie planet
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 // Funkcja aktualizująca filtry
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>Katalog planet</h1>
57
58 <div className="filters">
59 <label>
60 Typ planety:
61 <select
62 value={type}
63 onChange={(e) => updateFilters({ type: e.target.value })}
64 >
65 <option value="all">Wszystkie</option>
66 <option value="rocky">Skaliste</option>
67 <option value="gas-giant">Gazowe olbrzymy</option>
68 <option value="ice-giant">Lodowe olbrzymy</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 Tylko z wodą
79 </label>
80
81 <label>
82 Sortuj wg:
83 <select
84 value={sortBy}
85 onChange={(e) => updateFilters({ sortBy: e.target.value })}
86 >
87 <option value="name">Nazwa</option>
88 <option value="diameter">Rozmiar</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>Typ: {planet.type}</p>
99 <p>Średnica: {planet.diameter} km</p>
100 <p>Woda: {planet.hasWater ? 'Obecna' : 'Brak'}</p>
101 </Link>
102 </li>
103 ))}
104 </ul>
105
106 {filteredPlanets.length === 0 && (
107 <p>Nie znaleziono planet spełniających kryteria.</p>
108 )}
109
110 <button onClick={() => navigate('/')}>
111 Powrót do centrum kontroli
112 </button>
113 </div>
114 );
115}
116
117function PlanetDetails() {
118 const { planetId } = useParams();
119 const [searchParams, setSearchParams] = useSearchParams();
120 const navigate = useNavigate();
121
122 // Odczytanie parametrów zapytania
123 const activeTab = searchParams.get('tab') || 'overview';
124
125 // Znalezienie planety o danym ID
126 const planet = planetsData.find(p => p.id === planetId);
127
128 // Jeśli nie znaleziono planety
129 if (!planet) {
130 return (
131 <div className="planet-not-found">
132 <h1>Planeta nie istnieje!</h1>
133 <p>Nie znaleziono planety o identyfikatorze: {planetId}</p>
134 <button onClick={() => navigate('/planets')}>
135 Powrót do katalogu planet
136 </button>
137 </div>
138 );
139 }
140
141 // Zmiana aktywnej zakładki
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 Przegląd
156 </button>
157 <button
158 className={activeTab === 'composition' ? 'active' : ''}
159 onClick={() => changeTab('composition')}
160 >
161 Skład
162 </button>
163 <button
164 className={activeTab === 'exploration' ? 'active' : ''}
165 onClick={() => changeTab('exploration')}
166 >
167 Eksploracja
168 </button>
169 </div>
170
171 <div className="tab-content">
172 {activeTab === 'overview' && (
173 <div>
174 <h2>Przegląd planety {planet.name}</h2>
175 <p>Typ: {planet.type}</p>
176 <p>Średnica: {planet.diameter} km</p>
177 <p>Woda: {planet.hasWater ? 'Obecna' : 'Brak'}</p>
178 </div>
179 )}
180
181 {activeTab === 'composition' && (
182 <div>
183 <h2>Skład planety {planet.name}</h2>
184 <p>Tu będą informacje o składzie planety...</p>
185 </div>
186 )}
187
188 {activeTab === 'exploration' && (
189 <div>
190 <h2>Eksploracja planety {planet.name}</h2>
191 <p>Tu będą informacje o misjach eksploracyjnych...</p>
192 </div>
193 )}
194 </div>
195
196 <Link to="/planets">Powrót do katalogu planet</Link>
197 </div>
198 );
199}
200
201function App() {
202 return (
203 <BrowserRouter>
204 <div className="space-app">
205 <header>
206 <h1>Kosmiczny System Nawigacyjny</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>© 2150 Międzyplanetarna Agencja Kosmiczna</p>
220 </footer>
221 </div>
222 </BrowserRouter>
223 );
224}
225
226// Pozostałe komponenty
227function Dashboard() {
228 return (
229 <div className="dashboard">
230 <h1>Centrum Kontroli Misji</h1>
231 <p>Witaj w systemie nawigacji kosmicznej!</p>
232 <Link to="/planets">Przeglądaj katalog planet</Link>
233 </div>
234 );
235}
236
237function NotFound() {
238 return (
239 <div className="not-found">
240 <h1>Błąd nawigacji: 404</h1>
241 <p>Zagubiony w kosmosie! Ta strona nie istnieje.</p>
242 <Link to="/">Powrót do Centrum Kontroli</Link>
243 </div>
244 );
245}
246
247export default App;Najlepsze praktyki dla parametrów URL
- Używaj czytelnych nazw parametrów - powinny opisywać, co reprezentują
- Wybieraj odpowiedni typ parametrów - parametry ścieżki dla głównych zasobów, parametry zapytania dla filtrów
- Obsługuj brakujące parametry - zawsze zapewniaj wartości domyślne
- Waliduj parametry - sprawdzaj, czy wartości są poprawne przed użyciem
- Zachowuj stan parametrów zapytania - aktualizuj tylko te parametry, które się zmieniają
- Używaj parametrów do przechowywania stanu UI - ułatwia to udostępnianie i zapisywanie stanu
Podsumowanie
Parametry URL są potężnym narzędziem w nawigacji kosmicznej (i React Router). Pozwalają na:
- Identyfikację konkretnych zasobów (parametry ścieżki)
- Filtrowanie i sortowanie danych (parametry zapytania)
- Zapamiętywanie stanu interfejsu użytkownika
- Tworzenie udostępnialnych i zakładkowalnych linków
- Obsługę historii przeglądarki
Dzięki nim, użytkownicy mogą precyzyjnie nawigować do konkretnych lokalizacji w kosmicznej aplikacji, a ty jako programista możesz tworzyć interaktywne i przyjazne dla użytkownika interfejsy.
Kod do tej lekcji: App.jsx
1import React from 'react';
2import { BrowserRouter, Routes, Route, Link, useParams } from 'react-router-dom';
3
4// Lista planet
5const planets = [
6 { id: 'mars', name: 'Mars', emoji: '', distance: '225M km' },
7 { id: 'jupiter', name: 'Jowisz', emoji: '', distance: '628M km' },
8 { id: 'saturn', name: 'Saturn', emoji: '', distance: '1.2B km' },
9 { id: 'neptune', name: 'Neptun', emoji: '', distance: '4.3B km' },
10];
11
12// Strona główna z listą planet
13function PlanetList() {
14 return (
15 <div className="planet-list">
16 <h1>Katalog Planet</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// Szczegóły planety - używamy 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>Planeta nie znaleziona</h1>
43 <p>Nie odnaleziono planety o ID: {planetId}</p>
44 <Link to="/" className="back-link">← Wróć do katalogu</Link>
45 </div>
46 );
47 }
48
49 return (
50 <div className="planet-details">
51 <Link to="/" className="back-link">← Wróć do katalogu</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">Odległość od Ziemi:</span>
63 <span className="value">{planet.distance}</span>
64 </div>
65 <div className="info-item">
66 <span className="label">Parametr 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;Widzisz błąd w tej lekcji?
Sprawdź się
Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.
1. Jaka jest kluczowa różnica między komponentami Link a NavLink?
Zadania praktyczne w grze
- Układanie w poziomie
Ułóż elementy składni Route w React Router v6:
- Edytor kodu
Dynamiczne parametry URL
- Układanie w pionie
Uporządkuj hierarchię routingu w aplikacji kosmicznej: