Entdecken Sie essenzielle Navigationsmuster mit React Router v6. Lernen Sie deklaratives Routing, dynamische Routen, programmatische Navigation, verschachtelte Routen und Datenladestrategien für die Erstellung robuster und benutzerfreundlicher Webanwendungen.
React Router v6: Navigationsmuster für moderne Web-Apps meistern
React Router v6 ist eine leistungsstarke und flexible Routing-Bibliothek für React-Anwendungen. Sie ermöglicht es Ihnen, Single-Page-Anwendungen (SPAs) mit einem nahtlosen Benutzererlebnis zu erstellen, indem die Navigation ohne vollständige Seitenneuladungen verwaltet wird. Dieser Blogbeitrag befasst sich mit den wesentlichen Navigationsmustern von React Router v6 und vermittelt Ihnen das Wissen und die Beispiele, um robuste und benutzerfreundliche Webanwendungen zu erstellen.
Grundlagen von React Router v6 verstehen
Bevor wir uns mit spezifischen Mustern befassen, wollen wir einige grundlegende Konzepte wiederholen:
- Deklaratives Routing: React Router verwendet einen deklarativen Ansatz, bei dem Sie Ihre Routen als React-Komponenten definieren. Dies macht Ihre Routing-Logik klar und wartbar.
- Komponenten: Die Kernkomponenten umfassen
BrowserRouter
,HashRouter
,MemoryRouter
,Routes
undRoute
. - Hooks: React Router bietet Hooks wie
useNavigate
,useLocation
,useParams
unduseRoutes
, um auf Routing-Informationen zuzugreifen und die Navigation zu manipulieren.
1. Deklaratives Routing mit <Routes>
und <Route>
Das Fundament von React Router v6 ist das deklarative Routing. Sie definieren Ihre Routen mit den Komponenten <Routes>
und <Route>
. Die <Routes>
-Komponente dient als Container für Ihre Routen, und die <Route>
-Komponente definiert eine spezifische Route sowie die Komponente, die gerendert werden soll, wenn diese Route mit der aktuellen URL übereinstimmt.
Beispiel: Grundlegende Routenkonfiguration
Hier ist ein grundlegendes Beispiel für die Einrichtung von Routen für eine einfache Anwendung:
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Home from "./pages/Home";
import About from "./pages/About";
import Contact from "./pages/Contact";
function App() {
return (
} />
} />
} />
);
}
export default App;
In diesem Beispiel definieren wir drei Routen:
/
: Rendert dieHome
-Komponente./about
: Rendert dieAbout
-Komponente./contact
: Rendert dieContact
-Komponente.
Die BrowserRouter
-Komponente ermöglicht das auf der Browser-Historie basierende Routing. React Router gleicht die aktuelle URL mit den definierten Routen ab und rendert die entsprechende Komponente.
2. Dynamische Routen mit URL-Parametern
Dynamische Routen ermöglichen es Ihnen, Routen zu erstellen, die unterschiedliche Werte in der URL verarbeiten können. Dies ist nützlich, um Inhalte basierend auf einem eindeutigen Bezeichner wie einer Produkt-ID oder einer Benutzer-ID anzuzeigen. React Router v6 verwendet das :
-Symbol, um URL-Parameter zu definieren.
Beispiel: Anzeige von Produktdetails
Angenommen, Sie haben eine E-Commerce-Anwendung und möchten Details für jedes Produkt basierend auf seiner ID anzeigen. Sie können eine dynamische Route wie diese definieren:
import { BrowserRouter, Routes, Route, useParams } from "react-router-dom";
function ProductDetails() {
const { productId } = useParams();
// Produktdetails basierend auf productId abrufen
// ...
return (
Product Details
Product ID: {productId}
{/* Produktdetails hier anzeigen */}
);
}
function App() {
return (
} />
);
}
export default App;
In diesem Beispiel:
/products/:productId
definiert eine dynamische Route, bei der:productId
ein URL-Parameter ist.- Der
useParams
-Hook wird verwendet, um auf den Wert desproductId
-Parameters innerhalb derProductDetails
-Komponente zuzugreifen. - Sie können dann die
productId
verwenden, um die entsprechenden Produktdetails aus Ihrer Datenquelle abzurufen.
Internationalisierungsbeispiel: Umgang mit Sprachcodes
Für eine mehrsprachige Website könnten Sie eine dynamische Route verwenden, um Sprachcodes zu verarbeiten:
} />
Diese Route würde URLs wie /de/about
, /fr/about
und /es/about
entsprechen. Der lang
-Parameter kann dann verwendet werden, um die entsprechenden Sprachressourcen zu laden.
3. Programmatische Navigation mit useNavigate
Während deklaratives Routing ideal für statische Links ist, müssen Sie oft programmatisch navigieren, basierend auf Benutzeraktionen oder Anwendungslogik. React Router v6 stellt dafür den useNavigate
-Hook bereit. useNavigate
gibt eine Funktion zurück, mit der Sie zu verschiedenen Routen navigieren können.
Beispiel: Weiterleitung nach dem Absenden eines Formulars
Angenommen, Sie haben ein Formular, das abgesendet wird, und möchten den Benutzer nach erfolgreicher Übermittlung auf eine Erfolgsseite weiterleiten:
import { useNavigate } from "react-router-dom";
function MyForm() {
const navigate = useNavigate();
const handleSubmit = async (event) => {
event.preventDefault();
// Formulardaten senden
// ...
// Nach erfolgreicher Übermittlung zur Erfolgsseite weiterleiten
navigate("/success");
};
return (
);
}
export default MyForm;
In diesem Beispiel:
- Wir verwenden den
useNavigate
-Hook, um dienavigate
-Funktion zu erhalten. - Nachdem das Formular erfolgreich gesendet wurde, rufen wir
navigate("/success")
auf, um den Benutzer zur/success
-Route weiterzuleiten.
Zustand (State) während der Navigation übergeben
Sie können auch einen Zustand (State) zusammen mit der Navigation übergeben, indem Sie das zweite Argument von navigate
verwenden:
navigate("/confirmation", { state: { orderId: "12345" } });
Dies ermöglicht es Ihnen, Daten an die Zielkomponente zu übergeben, auf die mit dem useLocation
-Hook zugegriffen werden kann.
4. Verschachtelte Routen und Layouts
Verschachtelte Routen ermöglichen es Ihnen, hierarchische Routing-Strukturen zu erstellen, bei denen eine Route in einer anderen verschachtelt ist. Dies ist nützlich, um komplexe Anwendungen mit mehreren Navigationsebenen zu organisieren. Es hilft bei der Erstellung von Layouts, bei denen bestimmte UI-Elemente in einem Bereich der Anwendung konsistent vorhanden sind.
Beispiel: Benutzerprofil-Bereich
Angenommen, Sie haben einen Benutzerprofil-Bereich mit verschachtelten Routen zur Anzeige der Profilinformationen, Einstellungen und Bestellungen des Benutzers:
import { BrowserRouter, Routes, Route, Link } from "react-router-dom";
function Profile() {
return (
User Profile
-
Profile Information
-
Settings
-
Orders
} />
} />
} />
);
}
function ProfileInformation() {
return Profile Information Component
;
}
function Settings() {
return Settings Component
;
}
function Orders() {
return Orders Component
;
}
function App() {
return (
} />
);
}
export default App;
In diesem Beispiel:
- Die
/profile/*
-Route passt auf jede URL, die mit/profile
beginnt. - Die
Profile
-Komponente rendert ein Navigationsmenü und eine<Routes>
-Komponente, um die verschachtelten Routen zu verwalten. - Die verschachtelten Routen definieren die Komponenten, die für
/profile/info
,/profile/settings
und/profile/orders
gerendert werden sollen.
Das *
in der übergeordneten Route ist entscheidend; es bedeutet, dass die übergeordnete Route auf jeden Unterpfad passen soll, wodurch die verschachtelten Routen innerhalb der Profile
-Komponente korrekt zugeordnet werden können.
5. Umgang mit "Nicht gefunden" (404)-Fehlern
Es ist unerlässlich, Fälle zu behandeln, in denen der Benutzer zu einer nicht existierenden Route navigiert. React Router v6 macht dies mit einer Catch-All-Route einfach.
Beispiel: Implementierung einer 404-Seite
import { BrowserRouter, Routes, Route, Link } from "react-router-dom";
function NotFound() {
return (
404 - Not Found
The page you are looking for does not exist.
Go back to home
);
}
function App() {
return (
} />
} />
} />
);
}
In diesem Beispiel:
- Die Route
<Route path="*" element={<NotFound />} />
ist eine Catch-All-Route, die auf jede URL passt, die mit keiner der anderen definierten Routen übereinstimmt. - Es ist wichtig, diese Route am Ende der
<Routes>
-Komponente zu platzieren, damit sie nur dann greift, wenn keine andere Route passt.
6. Datenladestrategien mit React Router v6
React Router v6 enthält keine integrierten Datenlademechanismen wie sein Vorgänger (React Router v5 mit `useRouteMatch`). Es bietet jedoch die Werkzeuge, um verschiedene Datenladestrategien effektiv umzusetzen.
Option 1: Daten in Komponenten abrufen
Der einfachste Ansatz ist, Daten direkt in der Komponente abzurufen, die die Route rendert. Sie können den useEffect
-Hook verwenden, um Daten abzurufen, wenn die Komponente eingehängt wird oder wenn sich die URL-Parameter ändern.
import { useParams } from "react-router-dom";
import { useEffect, useState } from "react";
function ProductDetails() {
const { productId } = useParams();
const [product, setProduct] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
async function fetchProduct() {
try {
const response = await fetch(`/api/products/${productId}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
setProduct(data);
setLoading(false);
} catch (e) {
setError(e);
setLoading(false);
}
}
fetchProduct();
}, [productId]);
if (loading) return Loading...
;
if (error) return Error: {error.message}
;
if (!product) return Product not found
;
return (
{product.name}
{product.description}
);
}
export default ProductDetails;
Dieser Ansatz ist unkompliziert, kann aber zu Code-Duplizierung führen, wenn Sie Daten in mehreren Komponenten abrufen müssen. Er ist auch weniger effizient, da das Datenladen erst nach dem Einhängen der Komponente beginnt.
Option 2: Einen benutzerdefinierten Hook für das Datenladen verwenden
Um Code-Duplizierung zu reduzieren, können Sie einen benutzerdefinierten Hook erstellen, der die Logik für das Datenladen kapselt. Dieser Hook kann dann in mehreren Komponenten wiederverwendet werden.
import { useState, useEffect } from "react";
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
async function fetchData() {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const json = await response.json();
setData(json);
setLoading(false);
} catch (e) {
setError(e);
setLoading(false);
}
}
fetchData();
}, [url]);
return { data, loading, error };
}
export default useFetch;
Dann können Sie diesen Hook in Ihren Komponenten verwenden:
import { useParams } from "react-router-dom";
import useFetch from "./useFetch";
function ProductDetails() {
const { productId } = useParams();
const { data: product, loading, error } = useFetch(`/api/products/${productId}`);
if (loading) return Loading...
;
if (error) return Error: {error.message}
;
if (!product) return Product not found
;
return (
{product.name}
{product.description}
);
}
export default ProductDetails;
Option 3: Eine Routing-Bibliothek mit Datenladefähigkeiten verwenden (TanStack Router, Remix)
Bibliotheken wie TanStack Router und Remix bieten integrierte Datenlademechanismen, die sich nahtlos in das Routing integrieren. Diese Bibliotheken bieten oft Funktionen wie:
- Loaders: Funktionen, die ausgeführt werden, *bevor* eine Route gerendert wird, und es Ihnen ermöglichen, Daten abzurufen und an die Komponente zu übergeben.
- Actions: Funktionen, die Formularübermittlungen und Datenmutationen behandeln.
Die Verwendung einer solchen Bibliothek kann das Laden von Daten drastisch vereinfachen und die Leistung verbessern, insbesondere bei komplexen Anwendungen.
Serverseitiges Rendern (SSR) und Statische Seitengenerierung (SSG)
Für eine verbesserte SEO und Ladeleistung beim ersten Aufruf sollten Sie die Verwendung von SSR oder SSG mit Frameworks wie Next.js oder Gatsby in Betracht ziehen. Diese Frameworks ermöglichen es Ihnen, Daten auf dem Server oder während der Build-Zeit abzurufen und dem Client vorgerendertes HTML bereitzustellen. Dadurch entfällt die Notwendigkeit, dass der Client beim ersten Laden Daten abrufen muss, was zu einem schnelleren und SEO-freundlicheren Erlebnis führt.
7. Arbeiten mit verschiedenen Router-Typen
React Router v6 bietet verschiedene Router-Implementierungen für unterschiedliche Umgebungen und Anwendungsfälle:
- BrowserRouter: Verwendet die HTML5 History API (
pushState
,replaceState
) für die Navigation. Es ist die gebräuchlichste Wahl für Webanwendungen, die in einer Browserumgebung laufen. - HashRouter: Verwendet den Hash-Teil der URL (
#
) für die Navigation. Dies ist nützlich für Anwendungen, die ältere Browser unterstützen müssen oder auf Servern bereitgestellt werden, die die HTML5 History API nicht unterstützen. - MemoryRouter: Speichert die Historie Ihrer „URL“ im Speicher (ein Array von URLs). Nützlich in Umgebungen wie React Native und beim Testen.
Wählen Sie den Router-Typ, der am besten zu den Anforderungen und der Umgebung Ihrer Anwendung passt.
Fazit
React Router v6 bietet eine umfassende und flexible Routing-Lösung für React-Anwendungen. Durch das Verstehen und Anwenden der in diesem Blogbeitrag besprochenen Navigationsmuster können Sie robuste, benutzerfreundliche und wartbare Webanwendungen erstellen. Vom deklarativen Routing mit <Routes>
und <Route>
über dynamische Routen mit URL-Parametern, programmatische Navigation mit useNavigate
bis hin zu effektiven Datenladestrategien – React Router v6 ermöglicht es Ihnen, nahtlose Navigationserlebnisse für Ihre Benutzer zu schaffen. Erwägen Sie die Erkundung fortgeschrittener Routing-Bibliotheken und SSR/SSG-Frameworks für noch mehr Kontrolle und Leistungsoptimierung. Denken Sie daran, diese Muster an Ihre spezifischen Anwendungsanforderungen anzupassen und stets ein klares und intuitives Benutzererlebnis zu priorisieren.