Routennavigation
In diesem Kapitel lernst du, wie du mit React Router v6 eine Seitennavigation ohne Neuladen implementierst, einschließlich dynamischer Routen und dem Auslesen von Parametern.
Warum Routing verwenden?
Traditionelle Multi-Page-Websites fordern bei jedem Klick auf einen Link eine neue Seite vom Server an, was zu Weißbildschirm-Flackern führt.
Frontend-RoutingEs lässt JavaScript steuern, welche Komponente angezeigt wird, wenn sich die URL ändert, ohne Anfragen an den Server zu senden.
Vorteile:Reibungsloses Umschalten, das Erlebnis fühlt sich wie eine native App an。
Kernkonzepte von React Router v6
| Konzept | Zweck | Entsprechender Code |
|---|---|---|
| Routentabelle | Definiert die Zuordnung zwischen URLs und Komponenten | <Routes> + <Route> |
| Route-Outlet | Platzhalter, in dem untergeordnete Routen angezeigt werden | <Outlet /> |
| Navigationslink | Zum Navigieren klicken | <Link to="..."> |
| Dynamische Route | Variable in der URL | /post/:id |
| Parameter lesen | Den Wert aus der dynamischen Route abrufen | useParams() |
Installation und Konfiguration
$ npm install react-router-dom@6
Route-Konfiguration erstellen
Beispiel
import { createBrowserRouter } from 'react-router-dom'
import App from '../App'
import HomePage from '../pages/HomePage'
import PostPage from '../pages/PostPage'
// createBrowserRouter erstellt eine Router-Instanz
const router = createBrowserRouter([
{
path: '/', // App fungiert als Root-Layout
element: <App />,
children: [
{
index: true, // index: true bedeutet die Standard-Kindroute für den Pfad /
element: <HomePage />
},
{
path: 'post/:id', // Dynamische Route: :id stimmt mit jedem Wert überein
element: <PostPage />
}
]
}
])
export default router
Zwei Router-Modi:createBrowserRouterErzeugt saubere URLs (/post/1), erfordert eine Serverkonfiguration. Wenn die Bereitstellungsumgebung ungewiss ist, verwendecreateHashRouter, die URL enthält ein # (/#/post/1), und es ist keine Serverkonfiguration erforderlich.
Registriere den Router in main.jsx
Beispiel
import React from 'react'
import ReactDOM from 'react-dom/client'
import { RouterProvider } from 'react-router-dom'
import router from './router'
import './index.css'
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
{/* RouterProvider injiziert den Router in die App */}
<RouterProvider router={router} />
</React.StrictMode>
)
Verwende Outlet in App.jsx
Beispiel
import { Outlet } from 'react-router-dom'
import NavBar from './components/NavBar'
import './App.css'
function App() {
return (
<div className="app">
<NavBar />
<main className="container">
{/* Outlet ist die Ausgabestelle für verschachtelte Routen: Die von Kindrouten gematchte Komponente wird hier gerendert */}
<Outlet />
</main>
<footer className="footer">
<p>© 2024 BEISPIEL Blog. Betrieben mit React.</p>
</footer>
</div>
)
}
export default App
Link — Deklarative Navigation
LinkErsetzt den traditionellen<a>Tag und löst keinen Seiten-Refresh aus.
Beispiel
function BlogCard({ id, title, summary, date, category }) {
return (
<Link to={`/post/${id}`} className="card-link">
<div className="card">
<span className="tag">{Kategorie}</span>
<h3>{title}</h3>
<p>{summary}</p>
<span className="date">{Datum}</span>
</div>
</Link>
)
}
Verwende nicht
<a href="....html">— es bewirkt, dass der Browser eine neue Seite vom Server anfordert, und die gesamte React-App wird neu initialisiert. Verwende<Link to="...">um auf der Client-Seite ohne Aktualisierung umzuschalten.
useParams — Routenparameter lesen
Auf der Detailseite müssen Sie die Artikel-ID aus der URL extrahieren, um den entsprechenden Artikel zu finden.
Beispiel
function PostPage() {
// useParams gibt ein Objekt zurück, das die Parameter in der URL enthält
const { id } = useParams()
// Hinweis: id ist ein String; wenn Sie eine Zahl benötigen, verwenden Sie Number(id), um sie umzuwandeln
return (
<div>
<p>Aktuelle Artikel-ID:{id}</p>
</div>
)
}
useNavigate — Programmatische Navigation
In manchen Szenarien müssen Sie navigieren, ohne auf einen Link zu klicken (z. B. nach dem Absenden eines Formulars oder wenn ein Artikel nicht gefunden wird, zurück zur Startseite navigieren).
Beispiel
function PostPage() {
const navigate = useNavigate()
const article = null // Angenommen, der Artikel wird nicht gefunden
if (!article) {
// Wenn der Artikel nicht existiert, zur Startseite navigieren
return (
<div>
<p>Artikel nicht gefunden</p>
<button onClick={() => navigate('/')}>Zurück zur Startseite</button>
</div>
)
}
return <div>Artikeldetails...</div>
}
Vue3 vs React Router API-Vergleich
| Merkmal | Vue3 | React |
|---|---|---|
| Navigationslink | <RouterLink> | <Link> |
| Route-Outlet | <RouterView> | <Outlet> |
| Dynamische Route | /post/:id | /post/:id |
| Parameter lesen | useRoute().params | useParams() |
| Programmatische Navigation | useRouter().push() | useNavigate() |
Praxis: Vollständige Detailseite + Router-Integration
Schritt 1: BlogCard ändern, um Klick-Navigation zu unterstützen
Beispiel
import { Link } from 'react-router-dom'
function BlogCard({ id, title, summary, date, category }) {
return (
<Link to={`/post/${id}`} className="card-link">
<div className="card">
<span className="tag">{Kategorie}</span>
<h3>{title}</h3>
<p>{summary}</p>
<span className="date">{Datum}</span>
</div>
</Link>
)
}
export default BlogCard
Schritt 2: HomePage und PostPage erstellen
Beispiel
import { useState, useMemo } from 'react'
import BlogCard from '../components/BlogCard'
import CategoryFilter from '../components/CategoryFilter'
function HomePage() {
const [articles] = useState([
{ id: 1, title: 'Der komplette Leitfaden zu React für Anfänger', summary: 'React von Grund auf lernen', category: 'React', date: '2024-05-10',
content: '<h2>Warum React lernen?</h2><p>React ist derzeit eines der beliebtesten Frontend-Frameworks...</p>' },
{ id: 2, title: 'JS-Async-Programmierung erklärt', summary: 'Promise und async/await verstehen', category: 'JavaScript', date: '2024-05-08',
content: '<h2>Was ist Async?</h2><p>JS ist single-threaded; asynchrone Vorgänge können den Haupt-Thread freihalten...</p>' },
{ id: 3, title: 'CSS-Grid-Layout-Übung', summary: 'Mit Grid responsive Layouts erstellen', category: 'CSS', date: '2024-05-05',
content: '<h2>Erste Schritte mit Grid</h2><p>Grid ist ein zweidimensionales Layout-System...</p>' },
])
const [activeCategory, setActiveCategory] = useState('Alle')
const categories = useMemo(() => {
return ['Alle', ...new Set(articles.map(a => a.category))]
}, [articles])
const filteredArticles = useMemo(() => {
if (activeCategory === 'All') return articles
return articles.filter(a => a.category === activeCategory)
}, [articles, activeCategory])
return (
<div>
<h2 className="section-title">Neueste Artikel</h2>
<CategoryFilter
categories={categories}
activeCategory={activeCategory}
onCategoryChange={setActiveCategory}
/>
<p className="result-info">common{filteredArticles.length}Artikel</p>
{filteredArticles.length === 0 ? (
<p className="empty-tip">Noch keine Artikel in dieser Kategorie</p>
) : (
<div className="article-grid">
{filteredArticles.map(article => (
<BlogCard key={article.id} {...article} />
))}
</div>
)}
</div>
)
}
export default HomePage
Beispiel
import { useParams, Link } from 'react-router-dom'
import { useMemo } from 'react'
// Artikeldaten (werden in späteren Kapiteln aus externen Quellen geladen)
const articles = [
{ id: 1, title: 'Der vollständige Leitfaden zu React für Anfänger', category: 'React', date: '2024-05-10',
content: '<h2>Warum React lernen?</h2><p>React ist derzeit eines der beliebtesten Frontend-Frameworks...</p>' },
{ id: 2, title: 'JS Async-Programmierung erklärt', category: 'JavaScript', date: '2024-05-08',
content: '<h2>Was ist Async?</h2><p>JS ist single-threaded...</p>' },
]
function PostPage() {
const { id } = useParams()
// Artikel anhand der ID finden
const article = useMemo(() => {
return articles.find(a => a.id === Number(id))
}, [id])
// Artikel nicht gefunden
if (!article) {
return (
<div className="not-found">
<h2>Artikel nicht gefunden</h2>
<p>Artikel mit ID{id}wurde nicht gefunden.</p>
<Link to="/">Zurück zur Startseite</Link>
</div>
)
}
// Artikel existiert
return (
<article className="post-view">
<span className="category-tag">{article.category}</span>
<h1>{article.title}</h1>
<time>{article.date}</time>
{/* dangerouslySetInnerHTML ist gleichbedeutend mit Vues v-html, seien Sie sich der XSS-Risiken bewusst */}
<div
className="content"
dangerouslySetInnerHTML={{ __html: article.content }}
/>
<Link to="/" className="back-link">← Zurück zur Startseite</Link>
</article>
)
}
export default PostPage
dangerouslySetInnerHTMList die React-Version vonv-html. Der Name ist absichtlich lang, um Sie daran zu erinnern: Verwenden Sie ihn nicht, um von Benutzern generierte Inhalte zu rendern, es besteht ein XSS-Sicherheitsrisiko. Die Inhalte hier werden von den Entwicklern selbst geschrieben, daher ist es sicher.
Styles für PostPage hinzufügen
Beispiel
.post-view {
max-width: 720px;
margin: 0 auto;
}
.category-tag {
display: inline-block;
padding: 4px 12px;
background: #e3f2fd;
color: #1976d2;
border-radius: 12px;
font-size: 13px;
margin-bottom: 12px;
}
.post-view h1 {
font-size: 32px;
margin-bottom: 12px;
line-height: 1.4;
}
.post-view time {
display: block;
color: #999;
font-size: 14px;
margin-bottom: 30px;
}
.content {
line-height: 1.8;
font-size: 16px;
color: #333;
}
.content h2 {
margin: 24px 0 12px;
font-size: 22px;
}
.content p {
margin-bottom: 12px;
}
.back-link {
display: inline-block;
margin-top: 40px;
color: #1976d2;
text-decoration: none;
}
.not-found {
text-align: center;
padding: 60px 0;
}
Kapitelzusammenfassung
In diesem Kapitel haben Sie den Kern von React Router v6 kennengelernt: Routentabellenkonfiguration (createBrowserRouter), Link-Navigation, verschachteltes Outlet, dynamische Route /post/:id, useParams zum Lesen von Parametern und useNavigate für programmatische Navigation.
Jetzt hat der Blog ein echtes Multi-Page-Erlebnis — durchsuchen Sie die Liste auf der Startseite, klicken Sie, um die Detailseite aufzurufen und den vollständigen Inhalt zu lesen.
Andere Erweiterungen