Hirefullstack – Software Engineering & IT-Beratung aus Berlin
← Zur Übersicht
Kern 13 Min Lesezeit

Daten laden

await in der Komponente – und wie du Wasserfälle vermeidest

In einem Satz

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.

Dieselbe Aufgabe, zwei Welten
reines React im Browser
"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>;

}
Server-Komponente
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.

Gut zu wissen Woher die Daten kommen, ist egal

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..

nacheinander: 300 ms + 300 ms
const nutzer = await ladeNutzer(id);
const artikel = await ladeArtikel();   // wartet unnötig
gleichzeitig: 300 ms
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).

Tipp Der elegantere Weg: gar nicht warten

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..

memoization.tsx
// 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 () => { … });
Damit erübrigt sich das Durchreichen von Daten durch mehrere Ebenen.

Wo Daten hingehören

Nimm es, wenn …
  • +

    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

Lass es, wenn …
  • 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

Stolperstein Keine eigene API für den eigenen Server

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:

wege.txt
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.
Tipp Erst Weg 1 ausschließen

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.

Hirefullstack

Ihr braucht React-Verstärkung im Team?

Wir bauen seit Jahren React- und Next.js-Anwendungen für Kunden in ganz Deutschland – als einzelner Experte, als Verstärkung fürs Bestandsteam oder als komplettes Scrum-Team.

Projekt besprechen →