Dotychczas wszystkie nasze aplikacje składały się z jednego "widoku" – wszystkie komponenty renderowały się jednocześnie. Ale prawdziwe aplikacje webowe składają się z wielu stron: strona główna, profil użytkownika, ustawienia, produkty, szczegóły produktu, dashboard. Użytkownicy oczekują możliwości nawigacji między tymi stronami bez przeładowywania całej aplikacji.
W świecie Single Page Applications potrzebujemy client-side routing – mechanizmu, który zmienia zawartość strony w odpowiedzi na zmianę URL, ale bez wysyłania request do serwera. Do tego służy React Router – najpopularniejsza biblioteka do routingu w React.
W tym wpisie nauczymy się instalować i konfigurować React Router, tworzyć trasy (routes), linkować między nimi, przekazywać parametry przez URL, tworzyć chronione trasy (protected routes) wymagające autoryzacji, oraz poznamy wszystkie hooki do pracy z routingiem. To będzie praktyczny wpis – po nim Twoja aplikacja zamieni się w pełnoprawną aplikację wielostronicową!
Czym jest React Router?
React Router to biblioteka, która:
Synchronizuje UI z URL
Pozwala na deklaratywne definiowanie tras
Zapewnia nawigację bez przeładowania strony
Dostarcza hooki do pracy z historią przeglądarki, parametrami URL, itp.
Historia wersji:
React Router v5 – stara wersja (jeszcze spotykana w legacy projektach)
React Router v6 – aktualna wersja (której będziemy się uczyć)
Wersja 6 jest prostsza, bardziej intuicyjna i ma lepsze wsparcie dla TypeScript.
Instalacja React Router
npm install react-router-dom
To wszystko! react-router-dom zawiera wszystko czego potrzebujemy dla aplikacji webowych.
Podstawowa konfiguracja
Krok 1: Owinięcie aplikacji w BrowserRouter
// main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import App from './App';
import './index.css';
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
);
BrowserRouter używa History API przeglądarki do zarządzania URL.
Krok 2: Definiowanie tras
// App.tsx
import { Routes, Route } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
import Contact from './pages/Contact';
import NotFound from './pages/NotFound';
function App() {
return (
<div className="app">
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
<Route path="*" element={<NotFound />} />
</Routes>
</div>
);
}
export default App;
Co tu się dzieje?
<Routes> – kontener dla wszystkich tras
<Route> – definiuje pojedynczą trasę
path – ścieżka URL
element – komponent do wyrenderowania
path="*" – catch-all route (404)
Krok 3: Komponenty stron
// pages/Home.tsx
function Home() {
return (
<div>
<h1>Strona główna</h1>
<p>Witaj w naszej aplikacji!</p>
</div>
);
}
export default Home;
// pages/About.tsx
function About() {
return (
<div>
<h1>O nas</h1>
<p>Jesteśmy firmą...</p>
</div>
);
}
export default About;
// pages/NotFound.tsx
function NotFound() {
return (
<div>
<h1>404 - Strona nie znaleziona</h1>
<p>Przepraszamy, ta strona nie istnieje.</p>
</div>
);
}
export default NotFound;
Nawigacja – Link i NavLink
Link – podstawowa nawigacja
import { Link } from 'react-router-dom';
function Navigation() {
return (
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
<Link to="/contact">Contact</Link>
</nav>
);
}
<Link> renderuje <a> ale nie przeładowuje strony – nawigacja odbywa się przez JavaScript!
Nigdy nie używaj <a href="..."> w React Router! To spowoduje pełne przeładowanie aplikacji.
// Nawiguj forward
navigate('/dashboard');
// Nawiguj backward (replace history entry)
navigate('/dashboard', { replace: true });
// Nawiguj do poprzedniej strony
navigate(-1);
// Nawiguj do następnej strony (jeśli użytkownik cofnął się)
navigate(1);
// Nawiguj z state
navigate('/dashboard', { state: { from: 'login' } });
Zagnieżdżone trasy (Nested Routes)
Dla złożonych aplikacji możesz zagnieżdżać trasy:
// App.tsx
import { Routes, Route } from 'react-router-dom';
import Dashboard from './pages/Dashboard';
import Profile from './pages/dashboard/Profile';
import Settings from './pages/dashboard/Settings';
import Analytics from './pages/dashboard/Analytics';
function App() {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/dashboard" element={<Dashboard />}>
<Route path="profile" element={<Profile />} />
<Route path="settings" element={<Settings />} />
<Route path="analytics" element={<Analytics />} />
</Route>
</Routes>
);
}
Outlet – miejsce na nested routes
// pages/Dashboard.tsx
import { Outlet, Link } from 'react-router-dom';
function Dashboard() {
return (
<div className="dashboard">
<aside>
<h2>Dashboard Menu</h2>
<nav>
<Link to="/dashboard/profile">Profil</Link>
<Link to="/dashboard/settings">Ustawienia</Link>
<Link to="/dashboard/analytics">Analityka</Link>
</nav>
</aside>
<main>
{/* Tutaj renderują się zagnieżdżone trasy */}
<Outlet />
</main>
</div>
);
}
export default Dashboard;
URL i komponenty:
/dashboard → Dashboard (tylko sidebar)
/dashboard/profile → Dashboard + Profile
/dashboard/settings → Dashboard + Settings
Protected Routes (chronione trasy)
Często potrzebujesz tras dostępnych tylko dla zalogowanych użytkowników:
// components/ProtectedRoute.tsx
import { Navigate } from 'react-router-dom';
import { useAuth } from '../contexts/AuthContext';
interface ProtectedRouteProps {
children: React.ReactNode;
}
function ProtectedRoute({ children }: ProtectedRouteProps) {
// tutaj dostaniecie błąd, że nie można destrukturyzować pola /loading
// wiecie dlaczego, prawda ?
// jeżeli nie, sprawdzcie implementacje swojego hooka useAuth - wszystko stanie się jasne :)
const { isAuthenticated, loading } = useAuth();
if (loading) {
return <div>Sprawdzanie autoryzacji...</div>;
}
if (!isAuthenticated) {
// Przekieruj do logowania
return <Navigate to="/login" replace />;
}
return <>{children}</>;
}
export default ProtectedRoute;
To był obszerny, ale bardzo praktyczny wpis! Nauczyliśmy się:
✅ React Router – instalacja i konfiguracja
✅ Podstawowe trasy – Routes, Route, path, element
✅ Nawigacja – Link, NavLink, useNavigate
✅ Parametry URL – useParams, dynamic segments
✅ Query params – useSearchParams
✅ Zagnieżdżone trasy – Outlet, nested routing
✅ Protected Routes – autoryzacja, przekierowania
✅ Layout Routes – wspólny layout dla wielu tras
✅ Kompletny przykład – Blog App z routingiem
✅ Best Practices – organizacja, typowanie, lazy loading
React Router to fundament większości aplikacji React. Teraz masz wszystkie narzędzia do budowania wielostronicowych SPA z pełną nawigacją!
W kolejnym wpisie poznamy różne sposoby stylowania w React – CSS Modules, Styled Components, Tailwind CSS. Nauczymy się jak pisać responsywne, skalowalne style!