Kodokon kodokon.com

Modernes React: Server Components, use, useTransition, useOptimistic

Erkunde Server Components, das Lesen von Promises mit use und die optimistischen Updates von React 19.

11 Min. · 3 Fragen

Diese Lektion in Kodokon öffnen

React Server Components (RSC) zeichnen die Grenze zwischen Client und Server neu. Eine Server-Komponente läuft nur auf dem Server: Ihr Code gelangt nie ins Client-Bundle, sie kann async sein, direkt die Datenbank oder das Dateisystem lesen, und ihre Ausgabe wird als serialisierter Stream (das RSC-Payload) an den Browser gesendet, das React mit dem Client-Baum zusammenführt. Im Gegenzug hat sie keinen State, keine Effekte und keinen Zugriff auf den Browser: kein useState, kein useEffect, keine Event-Handler. Sie rendert auf dem Client nie erneut.

JSX
// Server component: never sent to the client.
export default async function NotesPage() {
  const notes = await db.notes.findAll();
  return (
    <ul>
      {notes.map((note) => (
        <li key={note.id}>{note.title}</li>
      ))}
    </ul>
  );
}
Eine asynchrone Server-Komponente fragt die Datenbank direkt ab.

Die Interaktivität lebt in Client-Komponenten, gekennzeichnet durch die Direktive 'use client' am Anfang der Datei. Diese Direktive markiert nicht „eine Client-Komponente“, sondern eine Grenze: Alles, was dieses Modul importiert, wandert ebenfalls auf die Client-Seite. Props, die die Grenze überschreiten, müssen serialisierbar sein: einfache Objekte, Arrays, Promises... aber niemals gewöhnliche Funktionen oder Klasseninstanzen.

JSX
'use client';

import { useState } from 'react';

export function LikeButton({ initialCount }) {
  const [count, setCount] = useState(initialCount);
  return (
    <button onClick={() => setCount(count + 1)}>
      {count} likes
    </button>
  );
}
Die Direktive 'use client' grenzt die interaktive Zone ab.

React 19 führt use ein, eine API, die den Wert eines Promise oder eines Kontexts liest. Anders als Hooks kann use innerhalb einer Bedingung oder einer Schleife aufgerufen werden. Bei einem Promise suspendiert es die Komponente bis zur Auflösung und stützt sich dabei auf die nächste Suspense-Grenze. Das idiomatische Muster: Eine Server-Komponente erzeugt das Promise, ohne es abzuwarten, gibt es als Prop weiter, und eine Client-Komponente konsumiert es mit use: Der Server beginnt, die Seite zu streamen, ohne auf die Daten zu warten.

JSX
import { use, Suspense } from 'react';

function Comments({ commentsPromise }) {
  const comments = use(commentsPromise);
  return comments.map((c) => (
    <p key={c.id}>{c.text}</p>
  ));
}

function Page({ commentsPromise }) {
  return (
    <Suspense fallback={<Spinner />}>
      <Comments commentsPromise={commentsPromise} />
    </Suspense>
  );
}
use suspendiert die Komponente, bis das Promise aufgelöst ist.

Auf der Interaktionsseite markiert useTransition ein Update als nicht dringend und stellt isPending bereit, damit du einen dezenten Indikator zeigen kannst, ohne die Eingabe zu blockieren. useOptimistic vervollständigt das Duo für Netzwerk-Mutationen: Du zeigst sofort den erhofften Zustand an, während eine asynchrone Action läuft; wenn die Action endet (Erfolg oder Fehlschlag), verwirft React den optimistischen Wert und zeigt wieder den echten Zustand, den aus der Source of Truth.

JSX
const [optimisticLikes, addOptimisticLike] =
  useOptimistic(likes, (count, delta) => count + delta);

function handleLike() {
  startTransition(async () => {
    addOptimisticLike(1);
    await saveLike();
    // At the end, React shows the real state again.
  });
}
Die Oberfläche reagiert sofort, der Server bestätigt danach.

Wissenscheck

Stelle sicher, dass du die wichtigsten Punkte dieser Lektion behalten hast.

  1. Was kann eine Server-Komponente nicht tun?
    • Als async deklariert werden und eine Anfrage awaiten
    • Die Datenbank direkt lesen
    • useState und Event-Handler verwenden
    • Client-Komponenten als Kinder rendern
  2. Welche Regel der Hooks darf die use-API brechen?
    • Außerhalb einer Komponente aufgerufen werden
    • Innerhalb einer Bedingung oder einer Schleife aufgerufen werden
    • Nach einem vorzeitigen Return des Moduls aufgerufen werden
    • Innerhalb einer Klasse aufgerufen werden
  3. Was passiert mit dem useOptimistic-Wert, wenn die asynchrone Action endet?
    • Er wird zum dauerhaften State der Komponente
    • Er wird verworfen, und der echte Zustand übernimmt wieder
    • Er wird mit dem echten Zustand zusammengeführt
    • Er wird bis zum nächsten manuellen Render behalten