Layouts, Templates & Navigation
Der Rahmen, der stehen bleibt, während sich der Inhalt ändert
Ein Layout umschließt alles darunter und bleibt beim Navigieren erhalten – samt Zustand. Genau das macht Wechsel innerhalb der App so schnell.
Kopfzeile, Navigation, Seitenleiste: Dinge, die auf vielen Seiten gleich aussehen. In Next.js schreibst du sie einmal in ein layout.tsxRahmen um alles darunter – Kopfzeile, Navigation, Seitenleiste. Bleibt beim Navigieren stehen und verliert seinen Zustand nicht.→ – und sie bleiben beim Seitenwechsel unangetastet stehen.
// Das Wurzel-Layout ist Pflicht. Nur hier stehen <html> und <body>.
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="de">
<body>
<Kopfzeile />
{children}
<Fusszeile />
</body>
</html>
);
} Layouts schachteln sich. Liegt in app/blog/layout.tsx noch eines, umschließt es alle Blog-Seiten – und wird selbst vom Wurzel-Layout umschlossen.
app/layout.tsx Kopf + Fuß
app/blog/layout.tsx Seitenleiste mit Kategorien
app/blog/page.tsx Artikelliste
app/blog/[slug]/page.tsx einzelner Artikel
Beim Wechsel von /blog nach /blog/hallo:
→ beide Layouts bleiben stehen
→ nur der innerste Teil wird getauscht Ein Layout ist der Bilderrahmen, die Seite das Bild darin. Beim Wechsel tauschst du das Bild – der Rahmen bleibt an der Wand hängen, mitsamt allem, was daran befestigt ist.
Weil das Layout stehen bleibt, behält es seinen Zustand: eine aufgeklappte Navigation bleibt offen, die Scrollposition der Seitenleiste bleibt erhalten, ein Video darin spielt weiter. Mit einem gewöhnlichen Seitenwechsel wäre all das weg.
Layout oder Template?
layout.tsx bleibt stehen, behält Zustand
template.tsx wird bei jeder Navigation neu aufgebaut
Template nehmen, wenn …
• eine Einblend-Animation jedes Mal laufen soll
• ein useEffect bei jedem Seitenwechsel feuern soll
• Zustand bewusst zurückgesetzt werden soll Im Zweifel: layout.tsxRahmen um alles darunter – Kopfzeile, Navigation, Seitenleiste. Bleibt beim Navigieren stehen und verliert seinen Zustand nicht.→. Ein template.tsxWie ein Layout, wird aber bei jeder Navigation neu aufgebaut. Für Dinge, die jedes Mal von vorn beginnen sollen – etwa eine Einblend-Animation.→ ist die Ausnahme und kostet den Vorteil, den Layouts überhaupt haben.
Der aktive Verweis
Eine Navigation soll zeigen, wo man gerade ist. Dafür braucht sie den aktuellen Pfad – und damit ist sie eine Client-KomponenteEine Komponente, die im Browser läuft und deshalb State, Hooks und Klicks kann. Erkennbar an `"use client"` oben in der Datei.→.
"use client";
import Link from "next/link";
import { usePathname } from "next/navigation";
const punkte = [
{ href: "/", label: "Start" },
{ href: "/blog", label: "Blog" },
{ href: "/kontakt", label: "Kontakt" },
];
export function Navigation() {
const pfad = usePathname();
return (
<nav>
{punkte.map((p) => {
const aktiv = p.href === "/" ? pfad === "/" : pfad.startsWith(p.href);
return (
<Link key={p.href} href={p.href} aria-current={aktiv ? "page" : undefined}>
{p.label}
</Link>
);
})}
</nav>
);
} Ein häufiger Reflex ist, "use client" in die layout.tsx zu schreiben. Damit wandert der ganze Rahmen in den Browser. Richtig ist: Das Layout bleibt Server-Komponente und bindet die kleine Navigations-Komponente ein.
Was ein Layout nicht kann
- +
Gemeinsame Gestaltung und Struktur
- +
Daten laden, die für den ganzen Bereich gelten (Menü, Nutzer)
- +
Metadata für alles darunter setzen
- −
Auf den aktuellen Pfad reagieren – ein Layout weiß nicht, welche Seite darin liegt
- −
searchParamslesen – die bekommt nur die Seite - −
Bei jeder Navigation etwas neu ausführen – dafür gibt es Templates
Das ist der Punkt der ganzen Sache – kann aber überraschen, wenn ein Layout Daten lädt, die sich pro Unterseite unterscheiden sollen. Solche Daten gehören in die Seite, nicht in den Rahmen.
▸ Genauer erklärt: Warum Navigation im App Router so schnell ist optional
Beim Klick auf ein next/linkInterner Verweis, der die Zielseite im Hintergrund vorlädt, sobald der Verweis sichtbar wird.→ lädt Next.js nicht die ganze Seite neu. Es holt nur den Teil, der sich ändert – und weiß dank der Layout-Struktur genau, welcher das ist.
Sichtbarer Link → Ziel wird im Hintergrund vorgeladen
Klick → nur der innerste Teil wird angefordert
Antwort → Layouts bleiben stehen, Inhalt wird ersetzt
Zurück-Knopf → Seite kommt sofort aus dem Router-Cache Der Router CacheDer Zwischenspeicher im Browser: Beim Zurücknavigieren zeigt Next.js die Seite sofort aus dem Speicher.→ im Browser hält kürzlich besuchte Seiten für kurze Zeit vor. Beim Zurücknavigieren erscheint deshalb sofort etwas – manchmal auch etwas Veraltetes. Nach einer Änderung räumt man ihn mit router.refresh() oder gezielt mit revalidatePath / revalidateTagGezieltes Für-ungültig-Erklären: nach dem Speichern genau die Seiten oder Daten neu holen lassen, die betroffen sind.→ auf.
Sitzt das schon?
4 Fragen zu dieser Lektion. Falsche Antworten landen in deiner Statistik.
Jetzt selbst schreiben
Die Navigation soll zeigen, wo man gerade ist. In Next.js käme der Pfad aus usePathname(); hier bekommst du ihn als Prop hereingereicht, damit die Logik prüfbar ist.
- □Der zutreffende Punkt bekommt
aria-current="page" - □
/blog/mein-artikelmarkiert den PunktBlog - □Die Startseite
/ist nur bei genau/aktiv, nicht überall
const PUNKTE = [ { href: "/", label: "Start" }, { href: "/blog", label: "Blog" }, { href: "/kontakt", label: "Kontakt" }, ]; // In Next.js: "use client" + const pfad = usePathname(); export function Navigation({ pfad }: { pfad: string }) { return ( <nav> {PUNKTE.map((p) => { // TODO: bestimmen, ob dieser Punkt aktiv ist const aktiv = false; return ( <a key={p.href} href={p.href} aria-current={aktiv ? "page" : undefined} style={{ marginRight: 12, fontWeight: aktiv ? 700 : 400 }} > {p.label} </a> ); })} </nav> ); } export default function App() { return ( <div style={{ fontFamily: "system-ui", padding: 16 }}> <Navigation pfad="/blog/mein-artikel" /> </div> ); }