Startseite / Artikel / React 19.2 SSR-Primitiven: Activity, cacheSignal und PPR erläutert

React 19.2 SSR-Primitiven: Activity, cacheSignal und PPR erläutert

Erfahren Sie, wie das neue Activity-Komponente, cacheSignal sowie die partielle Vorausrenderung in React 19.2 Entwicklern direkten Einfluss auf die Leistung der Serverrendering geben.

2240 Wörter

Die Arbeit zur Verbesserung der Leistung in React fällt meist in zwei Kategorien: die Beschleunigung und Vereinfachung der initialen Server-Renderung sowie das Vermeiden unnötiger Renderungen auf der Client-Seite, sobald die Anwendung geladen ist. Die beiden Teile dieses Artikels adressieren das Problem von entgegengesetzten Seiten aus, teilen aber dieselbe grundlegende Philosophie – nämlich dass Geschwindigkeit dadurch entsteht, React genau mitzuteilen, welche Aufgaben wichtig sind, welche verschoben werden können und welche überhaupt nicht ausgeführt werden sollten, anstatt einfach mehr Caching oder mehr Hardware einzusetzen. Der erste Teil behandelt die Server-Rendering-Funktionen sowie die neuen Primitiven, die mit React 19.2 eingeführt wurden; der zweite Teil konzentriert sich auf die alltäglichen Techniken auf der Client-Seite, die dafür sorgen, dass eine geladene Anwendung reaktiv bleibt.

Neu überdenken der Server-Rendering-Leistung in React 19.2

Die meisten Anleitungen zu „SSR-Leistung“ reduzieren sich auf das Hinzufügen weiterer Caching-Ebenen und das Hoffen auf das Beste. React 19.2, der im Oktober 2025 veröffentlicht wurde, bietet hingegen spezielle Primitiven, mit denen man die Serverarbeit direkt steuern kann. Diesen Release als kleine Aktualisierung zu betrachten bedeutet, echte Geschwindigkeitsvorteile zu verpassen – die unten aufgeführten Details sind es, die tatsächlich eine Verbesserung bewirken.

Halte Komponenten am Leben, anstatt sie zu zerstören

Ein wiederkehrendes Problem in SSR-Apps ist, dass Tabwechsel, das Öffnen von Modalen sowie Route-Übergänge Komponenten vollständig zerstören, ihren Zustand löschen und dazu führen, dass die Daten erneut abgerufen werden müssen. Die neue Activity-Komponente wurde speziell entwickelt, um dieses Problem zu lösen.

// old way — full unmount, state gone, effects re-run
{activeTab === 'analytics' && <AnalyticsPanel />}

// React 19.2 — stays alive, just deprioritized
<Activity mode={activeTab === 'analytics' ? 'visible' : 'hidden'}>
  <AnalyticsPanel />
</Activity>

Durch das Beibehalten des geladenen versteckten Inhalts anstelle dessen Zerstörung kann React bereits vor dem Klicken des Benutzers auf einen versteckten Activity-Block dessen Inhalt vorladen. Dieser Ansatz verringert laut Angaben die wahrgenommene Ladezeit bei Dashboards mit intensiver Serverseitiger Renderung erheblich, da es weder zu einer erneuten Abfrage noch zu einem Layoutwechsel kommt, sobald der Inhalt sichtbar wird.

Lassen Sie cacheSignal automatisch unvollendete Aufgaben bereinigen

Vor Version 19.2 konnten bei einer unterbrochenen Serverseitigen Renderung – beispielsweise wenn der Benutzer wegklickte oder eine Anfrage abbrach – die laufenden Abfragen sowie das gespeicherte Datenmaterial nicht erkennen, dass die Arbeit nicht mehr benötigt wurde. cacheSignal löst dieses Problem, indem es den React Server Components ein echtes Lebenszyklus-Signal zur Verfügung stellt, an das sie sich zur Bereinigung anschließen können.

async function getUserOrders(userId, { signal }) {
  const res = await fetch(`/api/orders/${userId}`, { signal });
  return res.json();
}

Sobald die Lebensdauer des Caches abläuft, löst das zugehörige Signal einen Abbruch aus, wodurch orphaned Anfragen verhindert werden, während von hoher Trafficbelastung aus weiterhin CPU-Ressourcen auf dem Server zu verbrauchen.

Bauen Sie eine statische Schale und streamen Sie den Rest

Partial Pre-rendering (PPR) ist die wichtigste SSR-Funktion in dieser Version. Dabei wird die statische Struktur einer Seite – Navigation, Layout, Fußzeile – einmal erstellt, direkt über ein Edge-CDN bereitgestellt und die dynamischen Teile hinter Suspense-Grenzen eingestreamt.

<Suspense fallback={<ProductSkeleton />}>
  <PartialPreRender>
    <PersonalizedRecommendations userId={user.id} />
  </PartialPreRender>
</Suspense>

Gruppiere mehrere Suspense-Enthüllungen zusammen

Zuvor, wenn mehrere Suspense-Grenzen ungefähr zur gleichen Zeit gelöst wurden, konnte die Benutzeroberfläche unter einem „Popcorn“-Effekt leiden, wobei Inhaltsfragmente nacheinander statt gemeinsam angezeigt wurden. React 19.2 gruppiert diese Anzeigungen, damit das Verhalten auf Client und Server konsistent bleibt, und fügt außerdem Unterstützung für Web Streams in Node.js hinzu, damit Teams eine feinere Kontrolle über das Streaming haben.

Diese APIs heben die Grenzen, nicht den Boden

Nichts davon ersetzt die Grundlagen. Sie müssen weiterhin N+1-Datenabrufmuster beseitigen und monolithische Pakete aufteilen, bevor diese Funktionen Ihnen überhaupt helfen können. React 19.2 verringert die minimale Menge an Optimierungsarbeiten nicht – er erhöht vielmehr die Obergrenze dafür, wie schnell eine gut optimierte Anwendung laufen kann. Es lohnt sich auch, die offiziellen Release-Notes zu React 19.2 sowie die in Next.js 16 eingeführten Turbopack-Einstellungen zu lesen, die gut mit PPR zusammenarbeiten.

Bis 2026 geht es bei der SSR-Leistung nicht darum, aggressiver zu cachen – sondern darum, React mitzuteilen, was warten kann, was gestreamt werden kann und was fehlerfrei abbrechen kann. React 19.2 bietet endlich das notwendige Vokabular, um dies auszudrücken.

Neben diesen spezifischen SSR-Mechanismen hängt viel davon ab, warum eine React-Anwendung schnell wirkt – insbesondere alltägliche Gewohnheiten, die unabhängig von der Render-Strategie oder der React-Version gelten. Während der vorherige Abschnitt sich auf Streaming, Vorrendern und Suspense am Serverseitigen Fokusierte, behandelt der folgende Teil die Client-Seiten-Muster, die dafür sorgen, dass jede React-Anwendung in der Praxis reaktiv bleibt.

Praktische Techniken für die tägliche React-Leistung

React rendernt standardmäßig bereits effizient. Erst wenn eine Anwendung wächst, beginnen unnötige Neu-Renderungen, überdimensionierte Listen, zu viel JavaScript sowie zu viele Netzwerkaufrufe, sich summierend auszuwirken. Die Lösung beinhaltet selten exotische Tricks – ein paar disziplinierte Gewohnheiten reichen in der Regel aus, um große Teile des Problems zu beseitigen.

Rendern nur das, was tatsächlich aktualisiert werden muss

Jede erneute Darstellung veranlasst React dazu, den Funktionskörper einer Komponente erneut auszuführen. Das ist an sich kein Problem – der eigentliche Aufwand entsteht durch die Wiederholung teurer Operationen, wenn sich eigentlich nichts Wesentliches geändert hat. Vermeiden Sie es, unverwandte Zustände in einer Komponente zu platzieren, die einen großen Teil Ihrer Benutzeroberfläche darstellt, da eine Aktualisierung dieses Zustands anschließend dazu führt, dass der gesamte Unterbaum zusammen mit ihm neu dargestellt wird. Teilen Sie die Komponenten stattdessen auf, sodass eine Aktualisierung nur den Teil der Benutzeroberfläche betrifft, den sie tatsächlich beeinflussen soll. Das Ziel ist nicht null erneute Darstellungen – sondern die Beseitigung der unnötigen.

Platzieren Sie den Zustand dort, wo er wirklich benötigt wird

Wehren Sie sich dagegen, jeden Zustandswert ganz nach oben in den Komponentenbaum zu bringen. Wenn nur eine einzige Komponente einen bestimmten Wert liest, dann gehört dieser Wert genau dorthin.

function SearchBox() {
  const [query, setQuery] = useState("");

  return (
    <input
      value={query}
      onChange={(e) => setQuery(e.target.value)}
    />
  );
}

Durch das Lokalisieren des Zustands auf diese Weise wird eingeschränkt, wie weit sich eine Aktualisierung auswirken kann, was wiederum unerwünschte Neuberechnungen an anderen Stellen im Baum reduziert. Als Faustregel sollte der Zustand in der Nähe des Components platziert werden, das ihn verwendet, anstatt weiter oben in der Hierarchie.

Werte ableiten statt speichern

Nicht alles gehört in useState. Wenn Sie bereits firstName und lastName verfolgen, gibt es keinen Grund, fullName zusätzlich getrennt zu speichern. Die verschwenderische Variante sieht so aus:

const [fullName, setFullName] = useState("");
useEffect(() => {
  setFullName(`${firstName} ${lastName}`);
}, [firstName, lastName]);

Ein einfacherer Ansatz besteht darin, den Wert während der Darstellung direkt zu berechnen:

const fullName = `${firstName} ${lastName}`;

Dadurch entfallen sowohl eine zusätzliche Zustandsvariable als auch ein unnötiger Effect. Im Allgemeinen benötigt ein Wert, der während der Darstellung dynamisch berechnet werden kann, vermutlich keinen Zustand.

Große Listen ohne Überlastung des DOMs verarbeiten

Das Rendern von Tausenden von Knoten gleichzeitig wird schnell teuer. Stellen Sie sich einen Chatbildschirm mit 10.000 Nachrichten vor – es ist nicht notwendig, dass alle davon gleichzeitig im DOM vorhanden sind. Für große Sammlungen sollten Sie eines der folgenden Verfahren nutzen:

  • Virtualisierung
  • Paginierung
  • Unendliches Scrollen

Durch Virtualisierung werden nur die Zeilen, die sich derzeit im Sichtbereich befinden, sowie ein kleiner Puffer zu jedem Zeitpunkt geladen; Bibliotheken wie react-window implementieren dieses Konzept für Sie. Dennoch sollten Sie Virtualisierung nicht reflexartig anwenden – eine Liste mit 50 Elementen benötigt sie fast sicherlich nicht.

Laden Sie Code erst dann, wenn er benötigt wird

Benutzer sollten keinen JavaScript-Code herunterladen müssen, der für Funktionen benötigt wird, die sie noch nicht geöffnet haben. Reacts lazy- und Suspense-APIs ermöglichen es Ihnen, diesen Code vom ursprünglichen Bundle zu trennen:

const Settings = lazy(() => import("./Settings"));

Dadurch wird der Settings-Komponente erst dann geladen, wenn sie tatsächlich dargestellt wird, anstatt bereits bei der initialen Seitenladung mitgeliefert zu werden. Dies ist sinnvoll für aufwändige oder selten genutzte Funktionen – Diagramme, Editor, Karten, Einstellungsseiten, große Dashboards – und führt in der Regel zu einer schnelleren initialen Ladezeit.

Interaktive Benutzeroberflächen unter Last reaktiv halten

Nicht jede Aktualisierung muss im Einklang mit den Eingaben des Benutzers erfolgen. Ein Suchfeld sollte sofort auf Tasteneingaben reagieren, selbst wenn die Filterung einer großen Datensammlung im Hintergrund mit geringerer Priorität abläuft. Die React-Hooks useTransition und useDeferredValue sind genau für solche Kompromisse konzipiert. Das Debouncing von Roheingaben erzielt einen ähnlichen Effekt:

const debouncedSearch = useDebounce(search, 500);

Anstatt bei jeder Tastenbetätigung eine Anfrage zu senden, wartet man, bis der Benutzer innehält. Solche Ansätze sind nützlich für Suchfelder, Filter, lange Listen sowie Dashboards mit vielen beweglichen Komponenten.

Reduzieren Sie überflüssige Netzwerkanfragen

Die Darstellungszeit ist nur ein Teil des Gesamtbildes – zu viele ausstehende Anfragen können dazu führen, dass eine App langsam wirkt, selbst wenn die eigentliche Darstellung schnell erfolgt. Je nach Situation sollten Sie in Betracht ziehen:

  • Antworten zu cachen
  • Anfragen zu duplizieren vermeiden
  • Ergebnisse paginieren
  • Sucheingaben zu debouncen
  • Anfragen stornieren, die nicht mehr relevant sind

Falls ein Benutzer schnell tippt

react
react performance
react performance optimization

möchten Sie wahrscheinlich nicht, dass drei separate Anfragen gleichzeitig ausgelöst werden. Das zugrundeliegende Prinzip bleibt einfach: Vermeiden Sie es, das Netzwerk mit Arbeiten zu belasten, die man eigentlich nicht benötigt.

Wenden Sie Memoisierung selektiv an

React stellt drei gängige Memoisierungsprimitiven bereit:

  • useMemo speichert das Ergebnis einer Berechnung im Cache.
  • useCallback speichert eine Funktionseintragung über mehrere Render-Vorgänge hinweg.
  • React.memo kann das Neurendern eines Komponenten vermeiden, wenn sich seine Props nicht geändert haben.

Ein typisches Beispiel:

const filteredUsers = useMemo(() => {
  return users.filter(user =>
    user.name.includes(search)
  );
}, [users, search]);

Doch Memoisierung ist nicht kostenlos – sie verursacht eigenen Overhead und erhöht die Komplexität des umliegenden Codes. Wenden Sie sie an, wenn eine Berechnung tatsächlich aufwändig ist, wenn ein Komponente ohne Grund ständig neu gerendert wird oder wenn eine stabile Referenz weiter im Codebaum wirklich wichtig ist. Investieren Sie keine Mühe in die Optimierung von Code, der kein messbares Problem verursacht.

Lassen Sie den Compiler einen Teil der Arbeit übernehmen

Eine neuere Ergänzung zur React-Entwicklungsumgebung ist der React Compiler, der viele dieser Optimierungen automatisch für Sie durchführen kann – indem er Werte, Funktionen und Komponenten merkt, ohne dass Sie dies in jedem Fall manuell tun müssen. Das bedeutet, Sie müssen nicht mehr automatisch auf Folgendes zurückgreifen:

useMemo(...)
useCallback(...)
React.memo(...)

Trotzdem beseitigt der React Compiler nicht die Notwendigkeit, zunächst zu prüfen, ob tatsächlich ein Leistungsproblem vorliegt. Die richtige Vorgehensweise besteht weiterhin darin, zunächst zu bestätigen, dass es ein echtes Problem gibt, anschließend den Compiler die von ihm möglichen Optimierungen anwenden zu lassen und nur dann auf manuelle Merkung zurückzugreifen, wenn Sie einen konkreten Grund dafür haben.

Geben Sie React stabile Identitäten zur Verfügung

Schlüssel teilen React mit, welcher Eintrag in einer Liste bei jeder Neuauflösung welcher ist. Verwenden Sie lieber eine stabile, eindeutige Eigenschaft der Daten als Schlüssel statt deren Position:

items.map(item => (
  <Item key={item.id} />
));

Vermeiden Sie es, den Array-Index als Schlüssel zu verwenden, da das Umordnen, Einfügen oder Entfernen von Elementen jeden Index unterhalb des Änderungspunkts verschiebt:

items.map((item, index) => (
  <Item key={index} />
));

Ein stabiler Schlüssel ermöglicht es React, korrekt zu erkennen, welche Einträge hinzugefügt, entfernt oder aktualisiert wurden, anstatt auf der Position zu schließen. Dasselbe Prinzip gilt für Objekte und Funktionen, die als Props übergeben werden: Das Erstellen eines völlig neuen Objekts oder Callbacks bei jeder Renderung untergräbt den Zweck eines gememorisierten Kindkomponenten, da seine Props jedes Mal anders aussehen, obwohl sich nichts Wesentliches geändert hat.

Erkennen Sie den tatsächlichen Engpass, bevor Sie handeln

Sobald Sie sich mit diesen Techniken wohlfühlen, verlassen Sie sich nicht auf Intuition, um zu entscheiden, was repariert werden muss. Öffnen Sie den React DevTools Profiler, um genau zu sehen, welche Komponenten gerendert werden und wie lange jede davon dauert. Bei Problemen, die über React selbst hinausgehen, kann das Performance-Panel des Browsers lange Aufgaben, langsame Skriptausführung, aufwändige Layout-Arbeiten oder Rendering-Engpässe aufzeigen. Anstatt anzunehmen, „diese Komponente wirkt langsam“, nutzen Sie diese Tools, um herauszufinden, warum sie langsam ist.

Überprüfen, ob die Korrektur tatsächlich geholfen hat

Nach der Anwendung einer Optimierung messen Sie erneut, anstatt anzunehmen, dass sie funktioniert hat. Prüfen Sie, ob die Renderzeit tatsächlich gesunken ist, ob das Bundle kleiner geworden ist und ob die Interaktionen responsiver wirken. Wenn sich nichts davon verbessert hat, war die Änderung möglicherweise von Anfang an nicht notwendig.

Checkliste vor dem Veröffentlichen

Vor der Veröffentlichung einer React-Anwendung prüfen Sie, ob Sie eine Benutzeroberfläche rendern, die Sie nicht benötigen, ob der Zustand am richtigen Ort gespeichert ist, ob Werte aufbewahrt werden, die stattdessen berechnet werden könnten, ob große Listen effizient verarbeitet werden, ob aufwändiger Code nur dann geladen wird, wenn er benötigt wird, ob Suchfunktionen und Interaktionen weiterhin reaktiv bleiben, ob unnötige API-Aufrufe erfolgen, ob die Memoisierung ein echtes Problem löst, ob der React Compiler eine Optimierung übernehmen könnte, ob Ihre Schlüssel stabil sind, ob Sie das eigentliche Engpassproblem gemessen haben und ob Sie anschließend die Verbesserung überprüft haben.

Letztendlich ist die beste Optimierung nicht die, die den meisten Code hinzufügt – sondern die, die dazu führt, dass React weniger unnötige Arbeit leistet.

Verwandte Artikel

  • Erläuterung zu teilweiser Vorkompilierung und paralleler Darstellung — Erfahren Sie, wie sowohl die teilweise Vorkompilierung von Next.js als auch die parallele Darstellung in React langsame Anwendungen beheben, indem sie den Frameworks ermöglichen, Aufgaben zu planen und in Echtzeit auszuführen, anstatt die Darstellungen als eine blockierende Einheit zu behandeln.
  • TC39-Vorschläge für 2026: Erläuterung zu Decorator, Temporal und Signals — Ein praktischer Überblick über drei TC39-Vorschläge – native Decorator, die Temporal-API und Signals – sowie deren Bedeutung für Full-Stack-JavaScript- und TypeScript-Entwickler.
  • React 19.2 erläutert: Activity, useEffectEvent und statische Darstellung — Erfahren Sie, wie der neue Activity-Komponente, der useEffectEvent-Hook sowie die teilweise statische Darstellung in React 19.2 versteckte Leistungsprobleme in modernen Benutzeroberflächen beheben.