Erschließen Sie skalierbare und dynamische UIs in Next.js. Unser umfassender Leitfaden behandelt Route Groups zur Organisation und Parallel Routes für komplexe Dashboards. Werden Sie jetzt zum Experten!
Meistern des Next.js App Routers: Ein tiefer Einblick in die Architektur von Route Groups und Parallel Routes
Die Veröffentlichung des Next.js App Routers markierte einen Paradigmenwechsel in der Art und Weise, wie Entwickler Webanwendungen mit dem beliebten React-Framework erstellen. Der App Router entfernte sich von den dateibasierten Konventionen des Pages Routers und führte ein leistungsfähigeres, flexibleres und serverzentriertes Modell ein. Diese Entwicklung ermöglicht es uns, hochkomplexe und performante Benutzeroberflächen mit größerer Kontrolle und Organisation zu erstellen. Zu den transformativsten eingeführten Funktionen gehören Route Groups und Parallel Routes.
Für Entwickler, die Anwendungen auf Unternehmensebene erstellen möchten, ist die Beherrschung dieser beiden Konzepte nicht nur vorteilhaft – sie ist unerlässlich. Sie lösen gängige architektonische Herausforderungen im Zusammenhang mit dem Layout-Management, der Routenorganisation und der Erstellung dynamischer, mehrteiliger Benutzeroberflächen wie Dashboards. Dieser Leitfaden bietet eine umfassende Untersuchung von Route Groups und Parallel Routes, von grundlegenden Konzepten bis hin zu fortgeschrittenen Implementierungsstrategien und Best Practices für ein globales Entwicklerpublikum.
Den Next.js App Router verstehen: Eine kurze Auffrischung
Bevor wir uns den Details widmen, werfen wir einen kurzen Blick auf die Kernprinzipien des App Routers. Seine Architektur basiert auf einem verzeichnisbasierten System, in dem Ordner URL-Segmente definieren. Spezielle Dateien innerhalb dieser Ordner definieren die Benutzeroberfläche und das Verhalten für dieses Segment:
page.js
: Die primäre UI-Komponente für eine Route, die sie öffentlich zugänglich macht.layout.js
: Eine UI-Komponente, die untergeordnete Layouts oder Seiten umschließt. Sie ist entscheidend für die gemeinsame Nutzung von UI über mehrere Routen hinweg, wie z. B. Kopf- und Fußzeilen.loading.js
: Eine optionale Benutzeroberfläche, die angezeigt wird, während Seiteninhalte geladen werden, basierend auf React Suspense.error.js
: Eine optionale Benutzeroberfläche zur Anzeige im Fehlerfall, die robuste Fehlergrenzen (Error Boundaries) schafft.
Diese Struktur, kombiniert mit der standardmäßigen Verwendung von React Server Components (RSCs), fördert einen Server-First-Ansatz, der die Leistung und Datenabrufmuster erheblich verbessern kann. Route Groups und Parallel Routes sind fortgeschrittene Konventionen, die auf diesem Fundament aufbauen.
Route Groups entmystifiziert: Organisation Ihres Projekts für Übersichtlichkeit und Skalierbarkeit
Wenn eine Anwendung wächst, kann die Anzahl der Routen unübersichtlich werden. Sie haben möglicherweise eine Reihe von Seiten für das Marketing, eine weitere für die Benutzerauthentifizierung und eine dritte für das Kern-Dashboard der Anwendung. Logisch gesehen sind dies separate Abschnitte, aber wie organisieren Sie sie in Ihrem Dateisystem, ohne Ihre URLs unübersichtlich zu machen? Genau dieses Problem lösen Route Groups.
Was sind Route Groups?
Eine Route Group ist ein Mechanismus, um Ihre Dateien und Routensegmente in logische Gruppen zu organisieren, ohne die URL-Struktur zu beeinflussen. Sie erstellen eine Route Group, indem Sie den Namen eines Ordners in Klammern setzen, zum Beispiel (marketing)
oder (app)
.
Der Ordnername in den Klammern dient rein organisatorischen Zwecken. Next.js ignoriert ihn vollständig bei der Bestimmung des URL-Pfades. Zum Beispiel wird die Datei unter app/(marketing)/about/page.js
unter der URL /about
bereitgestellt, nicht unter /(marketing)/about
.
Wichtige Anwendungsfälle und Vorteile von Route Groups
Während die einfache Organisation ein Vorteil ist, liegt die wahre Stärke von Route Groups in ihrer Fähigkeit, Ihre Anwendung in Abschnitte mit unterschiedlichen, gemeinsamen Layouts zu unterteilen.
1. Erstellen unterschiedlicher Layouts für Routensegmente
Dies ist der häufigste und leistungsstärkste Anwendungsfall. Stellen Sie sich eine Webanwendung mit zwei Hauptbereichen vor:
- Eine öffentliche Marketing-Website (Startseite, Über uns, Preise) mit einer globalen Kopf- und Fußzeile.
- Ein privates, authentifiziertes Benutzer-Dashboard (Dashboard, Einstellungen, Profil) mit einer Seitenleiste, benutzerspezifischer Navigation und einer anderen Gesamtstruktur.
Ohne Route Groups wäre die Anwendung unterschiedlicher Root-Layouts auf diese Abschnitte komplex. Mit Route Groups ist es unglaublich intuitiv. Sie können eine eindeutige layout.js
-Datei in jeder Gruppe erstellen.
Hier ist eine typische Dateistruktur für dieses Szenario:
app/
├── (marketing)/
│ ├── layout.js // Öffentliches Layout mit Marketing-Kopf-/Fußzeile
│ ├── page.js // Wird unter '/'
gerendert│ └── about/
│ └── page.js // Wird unter '/about'
gerendert├── (app)/
│ ├── layout.js // Dashboard-Layout mit Seitenleiste
│ ├── dashboard/
│ │ └── page.js // Wird unter '/dashboard'
gerendert│ └── settings/
│ └── page.js // Wird unter '/settings' gerendert
└── layout.js // Root-Layout (z.B. für <html>- und <body>-Tags)
In dieser Architektur:
- Jede Route innerhalb der
(marketing)
-Gruppe wird von(marketing)/layout.js
umschlossen. - Jede Route innerhalb der
(app)
-Gruppe wird von(app)/layout.js
umschlossen. - Beide Gruppen teilen sich das Root-Layout
app/layout.js
, was perfekt ist, um die globale HTML-Struktur zu definieren.
2. Ein Segment aus einem gemeinsamen Layout ausschließen
Manchmal muss eine bestimmte Seite oder ein Abschnitt vollständig aus dem übergeordneten Layout ausbrechen. Ein gängiges Beispiel ist ein Bezahlvorgang oder eine spezielle Landing-Page, die nicht die Navigation der Hauptseite haben sollte. Sie können dies erreichen, indem Sie die Route in eine Gruppe platzieren, die das übergeordnete Layout nicht teilt. Obwohl dies komplex klingt, bedeutet es einfach, einer Routengruppe ein eigenes Top-Level-layout.js
zu geben, das die `children` aus dem Root-Layout nicht rendert.
Praktisches Beispiel: Erstellen einer Anwendung mit mehreren Layouts
Lassen Sie uns eine minimale Version der oben beschriebenen Marketing/App-Struktur erstellen.
1. Das Root-Layout (app/layout.js
)
Dieses Layout ist minimal und gilt für jede einzelne Seite. Es definiert die wesentliche HTML-Struktur.
// app/layout.js
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
2. Das Marketing-Layout (app/(marketing)/layout.js
)
Dieses Layout enthält eine öffentlich zugängliche Kopf- und Fußzeile.
// app/(marketing)/layout.js
export default function MarketingLayout({ children }) {
return (
<div>
<header>Marketing Header</header>
<main>{children}</main>
<footer>Marketing Footer</footer>
</div>
);
}
3. Das App-Dashboard-Layout (app/(app)/layout.js
)
Dieses Layout hat eine andere Struktur und verfügt über eine Seitenleiste für authentifizierte Benutzer.
// app/(app)/layout.js
export default function AppLayout({ children }) {
return (
<div style={{ display: 'flex' }}>
<aside style={{ width: '200px', borderRight: '1px solid #ccc' }}>
Dashboard Sidebar
</aside>
<main style={{ flex: 1, padding: '20px' }}>{children}</main>
</div>
);
}
Mit dieser Struktur wird beim Navigieren zu /about
die Seite mit dem `MarketingLayout` gerendert, während beim Navigieren zu /dashboard
die Seite mit dem `AppLayout` gerendert wird. Die URL bleibt sauber und semantisch, während die Dateistruktur unseres Projekts perfekt organisiert und skalierbar ist.
Dynamische UIs mit Parallel Routes erschließen
Während Route Groups helfen, verschiedene Abschnitte einer Anwendung zu organisieren, lösen Parallel Routes eine andere Herausforderung: die Anzeige mehrerer, unabhängiger Seitenansichten innerhalb eines einzigen Layouts. Dies ist eine häufige Anforderung für komplexe Dashboards, Social-Media-Feeds oder jede Benutzeroberfläche, bei der verschiedene Panels gleichzeitig gerendert und verwaltet werden müssen.
Was sind Parallel Routes?
Parallel Routes ermöglichen es Ihnen, eine oder mehrere Seiten gleichzeitig innerhalb desselben Layouts zu rendern. Diese Routen werden mithilfe einer speziellen Ordnerkonvention namens Slots definiert. Slots werden mit der @folderName
-Syntax erstellt. Sie sind nicht Teil der URL-Struktur; stattdessen werden sie automatisch als Props an die nächstgelegene gemeinsame übergeordnete `layout.js`-Datei übergeben.
Wenn Sie beispielsweise ein Layout haben, das einen Team-Aktivitäts-Feed und ein Analyse-Diagramm nebeneinander anzeigen muss, können Sie zwei Slots definieren: `@team` und `@analytics`.
Die Kernidee: Slots
Stellen Sie sich Slots als benannte Platzhalter in Ihrem Layout vor. Die Layout-Datei akzeptiert diese Slots explizit als Props und entscheidet, wo sie gerendert werden sollen.
Betrachten Sie diese Layout-Komponente:
// Ein Layout, das zwei Slots akzeptiert: 'team' und 'analytics'
export default function DashboardLayout({ children, team, analytics }) {
return (
<div>
{children}
<div style={{ display: 'flex' }}>
{team}
{analytics}
</div>
</div>
);
}
Hier sind `children`, `team` und `analytics` allesamt Slots. `children` ist ein impliziter Slot, der der Standard-page.js
im Verzeichnis entspricht. `team` und `analytics` sind explizite Slots, die mit dem `@`-Präfix im Dateisystem erstellt werden müssen.
Wichtige Funktionen und Vorteile
- Unabhängiges Routen-Handling: Jede parallele Route (Slot) kann ihre eigenen Lade- und Fehlerzustände haben. Das bedeutet, Ihr Analyse-Panel kann einen Lade-Spinner anzeigen, während der Team-Feed bereits gerendert ist, was zu einer viel besseren Benutzererfahrung führt.
- Bedingtes Rendern: Sie können programmgesteuert entscheiden, welche Slots basierend auf bestimmten Bedingungen, wie dem Authentifizierungsstatus des Benutzers oder Berechtigungen, gerendert werden sollen.
- Sub-Navigation: Jeder Slot kann unabhängig navigiert werden, ohne die anderen Slots zu beeinflussen. Dies ist perfekt für tab-basierte Oberflächen oder Dashboards, bei denen der Zustand eines Panels vollständig von dem eines anderen getrennt ist.
Ein praxisnahes Szenario: Erstellen eines komplexen Dashboards
Lassen Sie uns ein Dashboard unter der URL /dashboard
entwerfen. Es wird einen Hauptinhaltsbereich, ein Team-Aktivitäts-Panel und ein Leistungsanalyse-Panel haben.
Dateistruktur:
app/
└── dashboard/
├── @analytics/
│ ├── page.js // UI für den Analytics-Slot
│ └── loading.js // Lade-UI speziell für Analytics
├── @team/
│ └── page.js // UI für den Team-Slot
├── layout.js // Das Layout, das die Slots orchestriert
└── page.js // Der implizite 'children'-Slot (Hauptinhalt)
1. Das Dashboard-Layout (app/dashboard/layout.js
)
Dieses Layout empfängt und ordnet die drei Slots an.
// app/dashboard/layout.js
export default function DashboardLayout({ children, analytics, team }) {
const isLoggedIn = true; // Durch echte Authentifizierungslogik ersetzen
return isLoggedIn ? (
<div>
<h1>Main Dashboard</h1>
{children}
<div style={{ marginTop: '20px', display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '20px' }}>
<div style={{ border: '1px solid blue', padding: '10px' }}>
<h2>Team Activity</h2>
{team}
</div>
<div style={{ border: '1px solid green', padding: '10px' }}>
<h2>Performance Analytics</h2>
{analytics}
</div>
</div>
</div>
) : (
<div>Please log in to view the dashboard.</div>
);
}
2. Die Slot-Seiten (z.B. app/dashboard/@analytics/page.js
)
Die page.js
-Datei jedes Slots enthält die Benutzeroberfläche für das jeweilige Panel.
// app/dashboard/@analytics/page.js
async function getAnalyticsData() {
// Simuliert eine Netzwerkanfrage
await new Promise(resolve => setTimeout(resolve, 3000));
return { views: '1.2M', revenue: '$50,000' };
}
export default async function AnalyticsPage() {
const data = await getAnalyticsData();
return (
<div>
<p>Page Views: {data.views}</p>
<p>Revenue: {data.revenue}</p>
</div>
);
}
// app/dashboard/@analytics/loading.js
export default function Loading() {
return <p>Lade Analysedaten...</p>;
}
Mit diesem Setup rendert Next.js das `DashboardLayout`, wenn ein Benutzer zu /dashboard
navigiert. Das Layout empfängt den gerenderten Inhalt von dashboard/page.js
, dashboard/@team/page.js
und dashboard/@analytics/page.js
als Props und platziert sie entsprechend. Entscheidend ist, dass das Analyse-Panel seinen eigenen loading.js
-Zustand für 3 Sekunden anzeigt, ohne das Rendern des restlichen Dashboards zu blockieren.
Umgang mit nicht übereinstimmenden Routen mit `default.js`
Eine entscheidende Frage stellt sich: Was passiert, wenn Next.js den aktiven Zustand eines Slots für die aktuelle URL nicht abrufen kann? Zum Beispiel könnte die URL bei einem ersten Laden oder einem Neuladen der Seite /dashboard
sein, was keine spezifischen Anweisungen dafür gibt, was in den Slots @team
oder `@analytics` angezeigt werden soll. Standardmäßig würde Next.js einen 404-Fehler rendern.
Um dies zu verhindern, können wir eine Fallback-UI bereitstellen, indem wir eine default.js
-Datei innerhalb der parallelen Route erstellen.
Beispiel:
// app/dashboard/@analytics/default.js
export default function DefaultAnalyticsPage() {
return (
<div>
<p>Keine Analysedaten ausgewählt.</p>
</div>
);
}
Wenn der Analytics-Slot nun nicht übereinstimmt, rendert Next.js den Inhalt von `default.js` anstelle einer 404-Seite. Dies ist unerlässlich, um eine reibungslose Benutzererfahrung zu schaffen, insbesondere beim erstmaligen Laden eines komplexen Setups mit parallelen Routen.
Kombination von Route Groups und Parallel Routes für fortgeschrittene Architekturen
Die wahre Stärke des App Routers wird erkannt, wenn man seine Funktionen kombiniert. Route Groups und Parallel Routes arbeiten wunderbar zusammen, um anspruchsvolle und hoch organisierte Anwendungsarchitekturen zu schaffen.
Anwendungsfall: Ein multimodaler Inhalts-Viewer
Stellen Sie sich eine Plattform wie eine Mediengalerie oder einen Dokumenten-Viewer vor, bei dem der Benutzer ein Element ansehen, aber auch ein modales Fenster öffnen kann, um dessen Details zu sehen, ohne den Kontext der Hintergrundseite zu verlieren. Dies wird oft als „Intercepting Route“ (abfangende Route) bezeichnet und ist ein leistungsstarkes Muster, das auf parallelen Routen basiert.
Lassen Sie uns eine Fotogalerie erstellen. Wenn Sie auf ein Foto klicken, öffnet es sich in einem Modal. Wenn Sie jedoch die Seite aktualisieren oder direkt zur URL des Fotos navigieren, sollte eine dedizierte Seite für dieses Foto angezeigt werden.
Dateistruktur:
app/
├── @modal/(..)(..)photos/[id]/page.js // Die abgefangene Route für das Modal
├── photos/
│ └── [id]/
│ └── page.js // Die dedizierte Fotoseite
├── layout.js // Root-Layout, das den @modal-Slot empfängt
└── page.js // Die Hauptgalerieseite
Erklärung:
- Wir erstellen einen parallelen Routen-Slot namens `@modal`.
- Der seltsam aussehende Pfad
(..)(..)photos/[id]
verwendet eine Konvention namens „Catch-all-Segmente“, um die Routephotos/[id]
von zwei Ebenen höher (vom Root aus) abzugleichen. - Wenn ein Benutzer von der Hauptgalerieseite (
/
) zu einem Foto navigiert, fängt Next.js diese Navigation ab und rendert die Seite des Modals im@modal
-Slot, anstatt eine vollständige Seitennavigation durchzuführen. - Die Hauptgalerieseite bleibt in der `children`-Prop des Layouts sichtbar.
- Wenn der Benutzer direkt
/photos/123
besucht, wird der Abfangmechanismus nicht ausgelöst, und die dedizierte Seite unterphotos/[id]/page.js
wird normal gerendert.
Dieses Muster kombiniert parallele Routen (den `@modal`-Slot) mit fortgeschrittenen Routing-Konventionen, um eine nahtlose Benutzererfahrung zu schaffen, die manuell nur sehr komplex zu implementieren wäre.
Best Practices und häufige Fallstricke
Best Practices für Route Groups
- Verwenden Sie beschreibende Namen: Wählen Sie aussagekräftige Namen wie
(auth)
,(marketing)
oder(protected)
, um Ihre Projektstruktur selbsterklärend zu machen. - Halten Sie die Struktur möglichst flach: Vermeiden Sie eine übermäßige Verschachtelung von Routengruppen. Eine flachere Struktur ist im Allgemeinen leichter zu verstehen und zu warten.
- Denken Sie an ihren Zweck: Verwenden Sie sie zur Layout-Partitionierung und Organisation, nicht zur Erstellung von URL-Segmenten.
Best Practices für Parallel Routes
- Stellen Sie immer eine `default.js` bereit: Fügen Sie bei jeder nicht-trivialen Verwendung von parallelen Routen eine `default.js`-Datei hinzu, um das erstmalige Laden und nicht übereinstimmende Zustände reibungslos zu handhaben.
- Nutzen Sie granulare Ladezustände: Platzieren Sie eine `loading.js`-Datei im Verzeichnis jedes Slots, um dem Benutzer sofortiges Feedback zu geben und UI-Wasserfälle zu vermeiden.
- Verwenden Sie sie für unabhängige UI: Parallele Routen glänzen, wenn der Inhalt jedes Slots wirklich unabhängig ist. Wenn Panels tief miteinander verbunden sind, könnte die Weitergabe von Props durch einen einzigen Komponentenbaum eine einfachere Lösung sein.
Häufige Fallstricke, die zu vermeiden sind
- Vergessen der Konventionen: Ein häufiger Fehler ist das Vergessen der Klammern `()` für Routengruppen oder des At-Symbols `@` für parallele Routen-Slots. Dies führt dazu, dass sie als normale URL-Segmente behandelt werden.
- Fehlende `default.js`: Das häufigste Problem bei parallelen Routen sind unerwartete 404-Fehler, weil keine Fallback-`default.js` für nicht übereinstimmende Slots bereitgestellt wurde.
- Missverständnis von `children`: Denken Sie daran, dass `children` in einem Layout, das parallele Routen verwendet, nur einer der Slots ist, der implizit dem `page.js` oder dem verschachtelten Layout im selben Verzeichnis zugeordnet ist.
Fazit: Die Zukunft der Webanwendungen gestalten
Der Next.js App Router bietet mit Funktionen wie Route Groups und Parallel Routes eine robuste und skalierbare Grundlage für die moderne Webentwicklung. Route Groups bieten eine elegante Lösung zur Organisation von Code und zur Anwendung unterschiedlicher Layouts, ohne die URL-Semantik zu beeinträchtigen. Parallel Routes ermöglichen die Erstellung dynamischer, mehrteiliger Benutzeroberflächen mit unabhängigen Zuständen, was bisher nur durch komplexes clientseitiges Zustandsmanagement erreichbar war.
Durch das Verständnis und die Kombination dieser leistungsstarken Architekturmuster können Sie über einfache Websites hinausgehen und anspruchsvolle, performante und wartbare Anwendungen erstellen, die den Anforderungen der heutigen Benutzer gerecht werden. Die Lernkurve mag steiler sein als beim klassischen Pages Router, aber der Gewinn in Bezug auf Anwendungsarchitektur und Benutzererfahrung ist immens. Beginnen Sie, mit diesen Konzepten in Ihrem nächsten Projekt zu experimentieren, und schöpfen Sie das volle Potenzial von Next.js aus.