Utilizziamo i cookie per migliorare la tua esperienza sul sito
CodeWorlds

Kompletna architektura routingu - Centrum Dowodzenia Nawigacją

Nawigatorze, dotarliśmy do ostatniego etapu naszej podróży przez Pas Asteroid! Czas zebrać wszystkie techniki nawigacyjne, które poznaliśmy, i zbudować kompletny system routingu - prawdziwe Centrum Dowodzenia Nawigacją dla naszej kosmicznej floty.

W tej lekcji zobaczymy, jak wszystkie elementy React Router współpracują ze sobą w jednej, spójnej aplikacji.

Architektura kompletnej aplikacji z routingiem

Budując aplikację z pełnym routingiem, musimy zaplanować kilka warstw:

  1. Warstwa uwierzytelniania - AuthContext + ProtectedRoute
  2. Warstwa nawigacji - NavLink z aktywnymi stylami
  3. Warstwa tras - zagnieżdżone Routes z Outlet
  4. Warstwa parametrów - dynamiczne ścieżki z useParams
  5. Warstwa przekierowań - obsługa 404 i zabezpieczeń

Struktura folderów

W większych aplikacjach warto zorganizować pliki związane z routingiem w logiczną strukturę:

1src/
2├── App.jsx              // Główny komponent z BrowserRouter
3├── routes/
4│   ├── AppRoutes.jsx    // Definicja wszystkich tras
5│   └── ProtectedRoute.jsx
6├── context/
7│   └── AuthContext.jsx  // Kontekst uwierzytelniania
8├── layouts/
9│   ├── MainLayout.jsx   // Layout z nawigacją i Outlet
10│   └── DashboardLayout.jsx
11├── pages/
12│   ├── HomePage.jsx
13│   ├── LoginPage.jsx
14│   ├── MissionDetail.jsx
15│   └── NotFound.jsx
16└── components/
17    └── Navigation.jsx   // NavLink menu

Taka organizacja pozwala łatwo zarządzać nawet rozbudowanymi aplikacjami z dziesiątkami tras.

Łączenie AuthContext z routingiem

Centralnym elementem jest AuthProvider owijający całą aplikację:

1function AuthProvider({ children }) {
2  const [user, setUser] = useState(null);
3
4  const login = (name) => setUser({ name });
5  const logout = () => setUser(null);
6
7  return (
8    <AuthContext.Provider value={{ user, login, logout }}>
9      {children}
10    </AuthContext.Provider>
11  );
12}
13
14// W App.jsx:
15function App() {
16  return (
17    <AuthProvider>
18      <BrowserRouter>
19        <Navigation />
20        <Routes>
21          {/* trasy publiczne i chronione */}
22        </Routes>
23      </BrowserRouter>
24    </AuthProvider>
25  );
26}

AuthProvider musi być na zewnątrz BrowserRouter, aby kontekst uwierzytelniania był dostępny we wszystkich komponentach tras.

Nawigacja z NavLink i warunkowym renderowaniem

Komponent nawigacji łączy NavLink (z aktywnymi stylami) z AuthContext (warunkowe wyświetlanie opcji):

1function Navigation() {
2  const { user, logout } = useAuth();
3
4  return (
5    <nav>
6      <NavLink to="/" className={({isActive}) => isActive ? 'active' : ''}>
7        Home
8      </NavLink>
9      <NavLink to="/missions" className={({isActive}) => isActive ? 'active' : ''}>
10        Missions
11      </NavLink>
12
13      {user ? (
14        <>
15          <NavLink to="/dashboard" className={({isActive}) => isActive ? 'active' : ''}>
16            Dashboard
17          </NavLink>
18          <span>Zalogowany: {user.name}</span>
19          <button onClick={logout}>Wyloguj</button>
20        </>
21      ) : (
22        <NavLink to="/login">Logowanie</NavLink>
23      )}
24    </nav>
25  );
26}

Dzięki temu nawigacja automatycznie reaguje na stan uwierzytelniania - zalogowany użytkownik widzi Dashboard i przycisk wylogowania, niezalogowany widzi link do logowania.

Zagnieżdżone trasy z layoutem

Sekcja misji wykorzystuje zagnieżdżone trasy z Outlet:

1function MissionsLayout() {
2  return (
3    <div className="missions-layout">
4      <aside>
5        <h3>Misje</h3>
6        <NavLink to="/missions/apollo">Apollo</NavLink>
7        <NavLink to="/missions/artemis">Artemis</NavLink>
8        <NavLink to="/missions/voyager">Voyager</NavLink>
9      </aside>
10      <main>
11        <Outlet />
12      </main>
13    </div>
14  );
15}
16
17// W konfiguracji tras:
18<Route path="/missions" element={<MissionsLayout />}>
19  <Route index element={<MissionsList />} />
20  <Route path=":missionId" element={<MissionDetail />} />
21</Route>

Index route (

<Route index />
) renderuje domyślną zawartość (listę misji), gdy użytkownik jest na
/missions
. Dynamiczny parametr
:missionId
obsługuje szczegóły konkretnej misji.

Kompletna konfiguracja tras

Oto jak wygląda pełna konfiguracja tras łącząca wszystkie poznane techniki:

1function App() {
2  return (
3    <AuthProvider>
4      <BrowserRouter>
5        <Navigation />
6        <Routes>
7          {/* Strona główna */}
8          <Route path="/" element={<HomePage />} />
9
10          {/* Logowanie */}
11          <Route path="/login" element={<LoginPage />} />
12
13          {/* Zagnieżdżone trasy z layoutem */}
14          <Route path="/missions" element={<MissionsLayout />}>
15            <Route index element={<MissionsList />} />
16            <Route path=":missionId" element={<MissionDetail />} />
17          </Route>
18
19          {/* Chroniona trasa */}
20          <Route path="/dashboard" element={
21            <ProtectedRoute>
22              <DashboardPage />
23            </ProtectedRoute>
24          } />
25
26          {/* Obsługa 404 */}
27          <Route path="*" element={<NotFound />} />
28        </Routes>
29      </BrowserRouter>
30    </AuthProvider>
31  );
32}

Kolejność elementów ma znaczenie:

  • Konkretne ścieżki (
    /
    ,
    /login
    ,
    /missions
    ) są dopasowywane jako pierwsze
  • Trasa
    path="*"
    musi być ostatnia - przechwytuje wszystko, co nie pasuje do żadnej zdefiniowanej trasy

Logowanie z zapamiętaniem ścieżki

Strona logowania wykorzystuje useNavigate i useLocation do przekierowania użytkownika z powrotem na stronę, z której został przekierowany:

1function LoginPage() {
2  const [name, setName] = useState('');
3  const { login } = useAuth();
4  const navigate = useNavigate();
5  const location = useLocation();
6
7  // Ścieżka, z której użytkownik został przekierowany
8  const from = location.state?.from?.pathname || '/dashboard';
9
10  const handleSubmit = (e) => {
11    e.preventDefault();
12    if (name.trim()) {
13      login(name);
14      navigate(from, { replace: true }); // replace: true usuwa /login z historii
15    }
16  };
17
18  return (
19    <form onSubmit={handleSubmit}>
20      <input value={name} onChange={(e) => setName(e.target.value)} />
21      <button type="submit">Zaloguj</button>
22    </form>
23  );
24}

Opcja

replace: true
w navigate jest kluczowa - dzięki niej użytkownik po zalogowaniu nie wróci na stronę logowania po kliknięciu "Wstecz" w przeglądarce.

Obsługa strony 404

Strona Not Found zawiera link powrotny do strony głównej:

1function NotFound() {
2  return (
3    <div className="not-found">
4      <h1>404</h1>
5      <p>Strona nie została odnaleziona</p>
6      <Link to="/">Wróć na stronę główną</Link>
7    </div>
8  );
9}

Podsumowanie architektury

Kompletna aplikacja z routingiem w React łączy następujące elementy:

| Element | Rola | Hook / Komponent | |---------|------|-------------------| | Kontener tras | Włącza routing | BrowserRouter | | Definicja tras | Mapuje URL na komponenty | Routes, Route | | Nawigacja | Linki z aktywnymi stylami | NavLink | | Zagnieżdżanie | Współdzielony layout | Outlet, Route children | | Parametry dynamiczne | Szczegóły elementów | useParams | | Nawigacja programowa | Przekierowanie po akcji | useNavigate | | Stan lokalizacji | Przekazywanie ukrytych danych | useLocation | | Ochrona tras | Wymuszanie logowania | ProtectedRoute + Navigate | | Obsługa błędów | Strony nieistniejące | Route path="*" | | Kontekst auth | Globalne dane użytkownika | createContext + useContext |

Wypróbuj kompletną aplikację w edytorze poniżej - zaloguj się, przejdź między misjami, sprawdź Dashboard i przetestuj stronę 404!

Vai a CodeWorlds