Używamy cookies, żeby zwiększyć Twoje doświadczenia na stronie
CodeWorlds

Konfiguracja routingu w aplikacjach kosmicznych

W poprzednim module poznaliśmy podstawy React Router jako systemu nawigacji międzyplanetarnej. Teraz zagłębimy się w szczegóły konfiguracji routingu w różnych rodzajach aplikacji kosmicznych, zarówno tych małych jak i złożonych wielomodułowych systemach.

Różne typy routerów w React Router

React Router dostarcza kilka typów routerów, które możemy wykorzystać w zależności od środowiska, w którym działa nasza aplikacja:

1. BrowserRouter

BrowserRouter
wykorzystuje HTML5 History API i jest najczęściej używanym routerem w nowoczesnych aplikacjach internetowych. Tworzy czyste, ładne URL-e bez hashtagu (#):

1import { BrowserRouter } from 'react-router-dom';
2
3function App() {
4  return (
5    <BrowserRouter>
6      {/* Komponenty routingu */}
7    </BrowserRouter>
8  );
9}

Ważne:

BrowserRouter
wymaga odpowiedniej konfiguracji serwera, który musi przekierowywać wszystkie żądania do pliku index.html (aby obsłużyć odświeżanie strony i bezpośrednie wejście na podstrony).

2. HashRouter

HashRouter
używa funkcji hash w URL (część po #). Jest to prostsze rozwiązanie, które nie wymaga konfiguracji serwera, ale tworzy mniej eleganckie URL-e:

1import { HashRouter } from 'react-router-dom';
2
3function App() {
4  return (
5    <HashRouter>
6      {/* Komponenty routingu */}
7    </HashRouter>
8  );
9}

Przykładowe URL-e przy użyciu HashRouter:

/#/mars
,
/#/jupiter

3. MemoryRouter

MemoryRouter
przechowuje historię nawigacji w pamięci (nie używa URL przeglądarki). Jest przydatny do testów i aplikacji działających w środowiskach bez przeglądarki:

1import { MemoryRouter } from 'react-router-dom';
2
3function App() {
4  return (
5    <MemoryRouter initialEntries={['/mars', '/jupiter']} initialIndex={1}>
6      {/* Komponenty routingu */}
7    </MemoryRouter>
8  );
9}

Zaawansowana konfiguracja Route

Komponent

Route
oferuje więcej opcji niż tylko podstawowe mapowanie ścieżki do elementu:

1. Ścieżki dynamiczne z parametrami

1<Route path="/planet/:planetId" element={<PlanetDetails />} />

Ta ścieżka pasuje do URL-i jak

/planet/mars
,
/planet/jupiter
, itd. Parametr
:planetId
jest dynamiczny i może być odczytany w komponencie.

2. Ścieżki opcjonalne

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

Znaki zapytania oznaczają parametry opcjonalne. Ta ścieżka pasuje do URL-i:

  • /missions
    (bez parametrów)
  • /missions/2150
    (tylko rok)
  • /missions/2150/06
    (rok i miesiąc)

3. Parametry z gwiazdką (catch-all)

1<Route path="/files/*" element={<FileExplorer />} />

Gwiazdka łapie wszystko po

/files/
, np.
/files/documents/reports/annual.pdf
.

Struktura routingu dla większych aplikacji kosmicznych

W obszernych aplikacjach kosmicznych, routing może stać się skomplikowany. Oto jak można go zorganizować:

1. Zagnieżdżone trasy

Możemy zagnieżdżać trasy, aby stworzyć hierarchiczną strukturę:

1function AppRoutes() {
2  return (
3    <Routes>
4      <Route path="/" element={<SpaceLayout />}>
5        <Route index element={<Dashboard />} />
6        <Route path="planets" element={<PlanetLayout />}>
7          <Route index element={<PlanetsList />} />
8          <Route path=":planetId" element={<PlanetDetails />} />
9        </Route>
10        <Route path="missions" element={<MissionLayout />}>
11          <Route index element={<MissionsDashboard />} />
12          <Route path="scheduled" element={<ScheduledMissions />} />
13          <Route path="completed" element={<CompletedMissions />} />
14        </Route>
15      </Route>
16      <Route path="/auth" element={<AuthLayout />}>
17        <Route path="login" element={<Login />} />
18        <Route path="register" element={<Register />} />
19      </Route>
20      <Route path="*" element={<NotFound />} />
21    </Routes>
22  );
23}

W powyższym przykładzie:

  • SpaceLayout
    jest głównym layoutem dla ścieżek zaczynających się od "/"
  • PlanetLayout
    jest layoutem dla wszystkich ścieżek z sekcji "planets"
  • Element
    index
    określa, co ma być renderowane dla ścieżki nadrzędnej (np. "/planets")

2. Route element vs. component

W React Router v6 używamy propsa

element
zamiast
component
z wcześniejszych wersji:

1// React Router v6 (aktualny)
2<Route path="/mars" element={<MarsBase />} />
3
4// React Router v5 (starszy)
5<Route path="/mars" component={MarsBase} />

Dlaczego to ważne? Syntax

element
pozwala na przekazanie wyrenderowanego elementu, co daje większą elastyczność:

1<Route
2  path="/mars"
3  element={
4    <MarsBase 
5      temperature={-60} 
6      oxygenLevel="low" 
7      waterAvailable={true}
8    />
9  } 
10/>

3. Outlet - wyświetlanie komponentów podścieżek

Komponent

Outlet
określa, gdzie w komponencie nadrzędnym mają być renderowane komponenty podścieżek:

1import { Outlet } from 'react-router-dom';
2
3function SpaceLayout() {
4  return (
5    <div className="space-layout">
6      <header>
7        <h1>Międzyplanetarny System Nawigacji</h1>
8        <nav>{/* Linki nawigacyjne */}</nav>
9      </header>
10      
11      <main>
12        {/* Tutaj będą renderowane komponenty podścieżek */}
13        <Outlet />
14      </main>
15      
16      <footer>
17        <p>Kosmiczne Centrum Dowodzenia &copy; 2150</p>
18      </footer>
19    </div>
20  );
21}

Konfiguracja z uwzględnieniem obsługi błędów

Dobrą praktyką jest dodanie globalnej obsługi błędów w naszym systemie routingu:

1function AppRoutes() {
2  return (
3    <Routes>
4      <Route path="/" element={<SpaceLayout />} errorElement={<GlobalError />}>
5        {/* Inne trasy */}
6      </Route>
7    </Routes>
8  );
9}
10
11function GlobalError() {
12  const error = useRouteError();
13  
14  return (
15    <div className="error-container">
16      <h1>Houston, mamy problem!</h1>
17      <p>Wystąpił błąd w systemie nawigacji:</p>
18      <pre>{error.message || "Nieznany błąd"}</pre>
19      <button onClick={() => window.location.href = "/"}>
20        Powrót do Centrum Dowodzenia
21      </button>
22    </div>
23  );
24}

Pełny przykład konfiguracji dla złożonej aplikacji kosmicznej

Poniżej znajduje się kompleksowy przykład konfiguracji routingu dla zaawansowanej aplikacji:

1import {
2  BrowserRouter,
3  Routes,
4  Route, 
5  Outlet, 
6  Navigate,
7  useRouteError
8} from 'react-router-dom';
9
10// Layouts
11function MainLayout() {
12  return (
13    <div className="main-layout">
14      <MainNavigation />
15      <div className="content">
16        <Outlet />
17      </div>
18      <Footer />
19    </div>
20  );
21}
22
23function AuthLayout() {
24  return (
25    <div className="auth-layout">
26      <div className="auth-container">
27        <Outlet />
28      </div>
29    </div>
30  );
31}
32
33// Error Components
34function GlobalError() {
35  const error = useRouteError();
36  return (
37    <div className="error-screen">
38      <h1>Błąd systemu nawigacji</h1>
39      <p>{error.message || "Nieznany błąd"}</p>
40    </div>
41  );
42}
43
44function NotFound() {
45  return (
46    <div className="not-found">
47      <h1>Zgubiony w przestrzeni kosmicznej</h1>
48      <p>Statek nie odnalazł żądanej lokalizacji.</p>
49    </div>
50  );
51}
52
53// Protected Route Component
54function ProtectedRoute({ children }) {
55  const isAuthenticated = useAuth();
56  
57  if (!isAuthenticated) {
58    return <Navigate to="/auth/login" replace />;
59  }
60  
61  return children;
62}
63
64// Main App
65function App() {
66  return (
67    <BrowserRouter>
68      <Routes>
69        {/* Główna sekcja z layoutem */}
70        <Route path="/" element={<MainLayout />} errorElement={<GlobalError />}>
71          <Route index element={<Dashboard />} />
72          
73          {/* Planety */}
74          <Route path="planets">
75            <Route index element={<PlanetsList />} />
76            <Route path=":planetId" element={<PlanetDetails />} />
77          </Route>
78          
79          {/* Misje - wymagają uwierzytelnienia */}
80          <Route path="missions" element={
81            <ProtectedRoute>
82              <MissionsLayout />
83            </ProtectedRoute>
84          }>
85            <Route index element={<MissionsDashboard />} />
86            <Route path="new" element={<NewMission />} />
87            <Route path=":missionId" element={<MissionDetails />} />
88            <Route path=":missionId/edit" element={<EditMission />} />
89          </Route>
90          
91          {/* Załoga */}
92          <Route path="crew">
93            <Route index element={<CrewList />} />
94            <Route path=":memberId" element={<CrewMemberProfile />} />
95          </Route>
96          
97          {/* Ustawienia - wymagają uwierzytelnienia */}
98          <Route path="settings" element={
99            <ProtectedRoute>
100              <Settings />
101            </ProtectedRoute>
102          } />
103        </Route>
104        
105        {/* Sekcja uwierzytelniania */}
106        <Route path="/auth" element={<AuthLayout />}>
107          <Route path="login" element={<Login />} />
108          <Route path="register" element={<Register />} />
109          <Route path="forgot-password" element={<ForgotPassword />} />
110          <Route path="reset-password/:token" element={<ResetPassword />} />
111        </Route>
112        
113        {/* Dokumentacja publiczna */}
114        <Route path="/docs/*" element={<DocsLayout />} />
115        
116        {/* Przekierowanie ze starej ścieżki na nową */}
117        <Route path="/old-missions" element={<Navigate to="/missions" replace />} />
118        
119        {/* Obsługa 404 */}
120        <Route path="*" element={<NotFound />} />
121      </Routes>
122    </BrowserRouter>
123  );
124}

Konfiguracja z React Router w środowisku developerskim

Podczas rozwijania aplikacji kosmicznej, warto skonfigurować narzędzia developerskie do pracy z React Router:

1. React Router DevTools

1// Tylko w trybie deweloperskim
2if (process.env.NODE_ENV === 'development') {
3  const ReactRouterDevTools = React.lazy(() => 
4    import('react-router-devtools').then(module => ({
5      default: module.ReactRouterDevTools
6    }))
7  );
8  
9  // Użycie w aplikacji
10  <React.Suspense fallback={null}>
11    <ReactRouterDevTools />
12  </React.Suspense>
13}

2. Konfiguracja webpack-dev-server dla BrowserRouter

Aby obsługiwać odświeżanie stron w środowisku developerskim z BrowserRouter, należy skonfigurować webpack-dev-server:

1// webpack.config.js
2module.exports = {
3  // inne ustawienia...
4  devServer: {
5    historyApiFallback: true, // Przekierowanie 404 do index.html
6    // inne ustawienia...
7  }
8};

Konfiguracja serwera produkcyjnego dla React Router

W środowisku produkcyjnym, serwer musi być skonfigurowany do obsługi wszystkich ścieżek React Router:

1. Dla serwera Node.js/Express:

1const express = require('express');
2const path = require('path');
3const app = express();
4
5// Serwowanie statycznych plików
6app.use(express.static(path.join(__dirname, 'build')));
7
8// Wszystkie żądania, które nie są do statycznych plików, przekierowane do index.html
9app.get('*', (req, res) => {
10  res.sendFile(path.join(__dirname, 'build', 'index.html'));
11});
12
13const PORT = process.env.PORT || 3000;
14app.listen(PORT, () => {
15  console.log(`Serwer nasłuchuje na porcie ${PORT}`);
16});

2. Dla serwera Apache (.htaccess):

1<IfModule mod_rewrite.c>
2  RewriteEngine On
3  RewriteBase /
4  RewriteRule ^index\.html$ - [L]
5  RewriteCond %{REQUEST_FILENAME} !-f
6  RewriteCond %{REQUEST_FILENAME} !-d
7  RewriteRule . /index.html [L]
8</IfModule>

3. Dla serwera Nginx:

1server {
2  listen 80;
3  server_name kosmiczna-aplikacja.pl;
4  
5  root /var/www/html;
6  index index.html;
7  
8  location / {
9    try_files $uri $uri/ /index.html;
10  }
11}

Podsumowanie

Prawidłowa konfiguracja routingu jest kluczowa dla funkcjonowania aplikacji kosmicznej (React). Kluczowe punkty:

  1. Wybierz odpowiedni typ routera - zwykle
    BrowserRouter
    dla nowoczesnych aplikacji
  2. Twórz hierarchiczną strukturę tras - używaj zagnieżdżonych tras z
    Outlet
    dla lepszej organizacji
  3. Zaimplementuj obsługę błędów - używaj
    errorElement
    dla obsługi błędów
  4. Zabezpiecz prywatne trasy - stwórz komponent
    ProtectedRoute
    do ochrony dostępu
  5. Skonfiguruj serwer produkcyjny - upewnij się, że serwer przekierowuje wszystkie żądania do index.html

Z dobrze skonfigurowanym systemem nawigacji, użytkownicy twojej kosmicznej aplikacji będą mogli swobodnie podróżować między różnymi jej częściami, bez obaw o zagubienie się w przestrzeni kosmicznej (błędy 404).

Przejdź do CodeWorlds