Routing über Ordner
Adressen entstehen aus dem Dateibaum – mit ein paar Sonderzeichen
Jeder Ordner in app/ ist ein Stück der Adresse, jede page.tsx macht sie aufrufbar. Klammern um Ordnernamen ändern, was das Segment bedeutet.
Es gibt keine Routen-Datei, die du pflegen musst. Wo eine Seite liegt, das ist ihre Adresse. Diese Lektion zeigt die vier Klammer-Schreibweisen, mit denen du davon abweichst.
Der Normalfall
app/
page.tsx → /
kontakt/
page.tsx → /kontakt
blog/
page.tsx → /blog
[slug]/
page.tsx → /blog/beliebiger-wert [slug] ist ein Dynamisches SegmentEin Ordner in eckigen Klammern, `[slug]`, der für jeden beliebigen Wert an dieser Stelle steht.`[...alles]` fängt beliebig viele Stufen ab, `[[...alles]]` zusätzlich auch den leeren Fall.→: Der Ordnername in eckigen Klammern steht für einen beliebigen Wert. Was tatsächlich in der Adresse stand, bekommt die Seite als Parameter.
export default async function Page({
params,
}: {
params: Promise<{ slug: string }>;
}) {
const { slug } = await params;
const artikel = await ladeArtikel(slug);
return <h1>{artikel.titel}</h1>;
} Ältere Beispiele im Netz greifen direkt mit params.slug zu. Seit Version 15 ergibt das undefined bzw. eine Warnung. Immer erst const { slug } = await params;.
Die vier Klammern
[slug] ein Wert /blog/hallo
[...pfad] beliebig viele /docs/a/b/c
[[...pfad]] auch gar keiner /docs und /docs/a/b
(gruppe) taucht NICHT in der Adresse auf Die Route-GruppeEin Ordner in runden Klammern, `(marketing)`, der nur zum Sortieren dient und nicht in der Adresse auftaucht.→ in runden Klammern ist reine Ordnung: app/(marketing)/preise/page.tsx liegt unter /preise, nicht unter /marketing/preise. Praktisch, um Bereichen ein eigenes Layout zu geben, ohne die Adressen zu verändern.
app/
(marketing)/
layout.tsx ← Layout nur für diesen Bereich
page.tsx → /
preise/page.tsx → /preise
(app)/
layout.tsx ← ein anderes Layout
dashboard/page.tsx → /dashboard Navigieren
import Link from "next/link";
<Link href="/blog">Zum Blog</Link>
<Link href={`/blog/${artikel.slug}`}>{artikel.titel}</Link>
// Programmgesteuert – nur in Client-Komponenten:
"use client";
import { useRouter } from "next/navigation";
const router = useRouter();
router.push("/danke"); next/linkInterner Verweis, der die Zielseite im Hintergrund vorlädt, sobald der Verweis sichtbar wird.→ lädt die Zielseite im Hintergrund vor, sobald der Verweis sichtbar wird, und wechselt ohne kompletten Seitenneuaufbau. Ein normales <a href> wirft die ganze Anwendung weg und lädt neu.
useRouter gibt es zweimal. Im App Router kommt es aus next/navigation. Der Import aus next/router gehört zum alten Pages Router und wirft zur Laufzeit einen Fehler.
Was noch in einen Ordner darf
app/blog/
page.tsx die Seite
layout.tsx Rahmen für /blog und alles darunter
loading.tsx Anzeige, solange geladen wird
error.tsx Auffangnetz
BlogKarte.tsx ganz normale Komponente, erzeugt KEINE Adresse
utils.ts Hilfsfunktionen, ebenfalls harmlos Nur die reservierten Namen haben eine Bedeutung. Alles andere kannst du dort ablegen, wo es gebraucht wird – Komponenten müssen nicht in einen zentralen components/-Ordner wandern.
▸ Genauer erklärt: statische Adressen aus dynamischen Segmenten optional
Eine Seite mit [slug] wird standardmäßig bei jeder Anfrage neu erzeugt – Next.js weiß ja nicht, welche Werte es gibt. Mit generateStaticParamsSagt Next.js beim Bauen, welche konkreten Werte ein dynamisches Segment annehmen soll – damit daraus statische Seiten werden.→ sagst du es ihm, und aus der dynamischen Seite werden echte statische Dateien.
export async function generateStaticParams() {
const artikel = await ladeAlleArtikel();
return artikel.map((a) => ({ slug: a.slug }));
}
// Ergebnis: beim Bauen entsteht je Artikel eine fertige Seite. Ruft jemand einen Slug auf, der nicht in der Liste stand, erzeugt Next.js die Seite bei Bedarf und merkt sie sich. Willst du das nicht, setzt du export const dynamicParams = false – dann gibt es für alles andere eine 404.
Sitzt das schon?
5 Fragen zu dieser Lektion. Falsche Antworten landen in deiner Statistik.