Daten laden
await in der Komponente – und wie du Wasserfälle vermeidest
In einer Server-Komponente holst du Daten direkt mit await. Kein useEffect, kein Ladezustand, kein Wettrennen – dafür eine neue Falle: Ladevorgänge, die unnötig nacheinander laufen.
Das ist die Stelle, an der Next.js am deutlichsten einfacher ist als reines React. Was dort drei Zustände und einen Effect brauchte, ist hier eine Zeile.
"use client";
function Liste() {
const [daten, setDaten] = useState(null);
const [laedt, setLaedt] = useState(true);
const [fehler, setFehler] = useState(null);
useEffect(() => {
let aktuell = true;
fetch("/api/artikel")
.then((r) => r.json())
.then((d) => aktuell && setDaten(d))
.catch(setFehler)
.finally(() => setLaedt(false));
return () => { aktuell = false; };
}, []);
if (laedt) return <p>Lädt …</p>;
…
} export default async function Liste() {
const artikel = await db.artikel.findMany();
return (
<ul>
{artikel.map((a) => (
<li key={a.id}>{a.titel}</li>
))}
</ul>
);
} Kein Ladezustand, weil der Nutzer die Seite erst sieht, wenn die Daten da sind. Kein Wettrennen, weil nichts parallel im Browser läuft. Und keine API dazwischen, weil du schon auf dem Server bist.
fetch zu einer fremden API, ein Datenbankzugriff, das Dateisystem – alles erlaubt. Der Code läuft auf dem Server, also gelten dort auch dessen Möglichkeiten.
Die neue Falle: der Wasserfall
Zwei await hintereinander bedeuten: Der zweite startet erst, wenn der erste fertig ist. Wenn sie nichts voneinander wissen, ist das verschenkte Zeit – ein WasserfallZwei Ladevorgänge, die nacheinander laufen, obwohl sie nebeneinander laufen könnten – die häufigste Bremse.→.
const nutzer = await ladeNutzer(id);
const artikel = await ladeArtikel(); // wartet unnötig const [nutzer, artikel] = await Promise.all([
ladeNutzer(id),
ladeArtikel(),
]); Nacheinander ist nur richtig, wenn der zweite Aufruf das Ergebnis des ersten braucht – etwa ladeBestellungen(nutzer.id).
Statt alles einzusammeln, bevor irgendetwas erscheint, kannst du jeden Teil selbst laden lassen und in <Suspense> einpacken. Dann erscheint jeder Bereich, sobald er fertig ist. Dazu kommt die Lektion zum Streaming.
Dieselbe Anfrage mehrfach
Wenn Layout und Seite beide den angemeldeten Nutzer brauchen, schreibst du den Aufruf einfach zweimal hin. Next.js führt ihn trotzdem nur einmal aus – das nennt sich Request MemoizationDerselbe `fetch` mehrfach in einem Seitenaufbau wird nur einmal wirklich ausgeführt.→.
// app/layout.tsx
const nutzer = await ladeNutzer(); // führt die Anfrage aus
// app/page.tsx
const nutzer = await ladeNutzer(); // nimmt dasselbe Ergebnis
// Gilt für fetch automatisch. Für eigene Funktionen:
import { cache } from "react";
export const ladeNutzer = cache(async () => { … }); Wo Daten hingehören
- +
In die Komponente, die sie anzeigt – auch tief im Baum
- +
Ins Layout, wenn sie für den ganzen Bereich gelten (Menü, Nutzer)
- +
In eine gemeinsame Funktion mit
cache(), wenn mehrere sie brauchen
- −
In einen
useEffect– das ist der Umweg, den du gerade losgeworden bist - −
In eine eigene API-Route, nur um sie danach selbst aufzurufen
- −
Ganz nach oben, um sie dann durch fünf Ebenen zu reichen
Ein häufiger Reflex: erst eine route.ts bauen und sie dann aus der Server-Komponente mit fetch("/api/…") aufrufen. Das ist ein Umweg über das Netzwerk zu sich selbst. Ruf die Funktion direkt auf. Eine Route HandlerEine `route.ts`, die auf eine Adresse antwortet, ohne eine Seite zu sein – der Weg zu einer eigenen API.→ brauchst du erst, wenn jemand von außen zugreifen soll.
▸ Genauer erklärt: Client-Komponenten, die Daten brauchen optional
Eine Client-Komponente darf nicht async sein und keinen Datenbankzugriff machen. Für sie gibt es drei Wege – in dieser Reihenfolge:
1. Von oben hereinreichen
Server-Komponente lädt, gibt das Ergebnis als Prop weiter.
Deckt die allermeisten Fälle ab.
2. Server Action aufrufen
Für Daten, die erst durch eine Nutzeraktion nötig werden.
3. Im Browser laden
Wenn es wirklich clientseitig sein muss: TanStack Query o. Ä.
gegen einen Route Handler. Sehr oft lässt sich die Grenze einfach anders ziehen: Die Client-Komponente wird kleiner, das Laden bleibt auf dem Server. Das ist fast immer die bessere Lösung als eine zweite Ladeschicht im Browser.
Sitzt das schon?
5 Fragen zu dieser Lektion. Falsche Antworten landen in deiner Statistik.