
React hat die Art und Weise, wie wir Benutzeroberflächen erstellen, grundlegend verändert, indem es ein komponentenbasiertes Design eingeführt hat, das Effizienz und Wiederverwendbarkeit fördert. Seine deklarative Herangehensweise und die komponentenbasierte Struktur haben bei Entwicklern großen Anklang gefunden. Doch wenn deine Projekte immer komplexer werden, kannst du aufgrund der Rendering- und Datenabrufmethoden auf performance-Probleme stoßen.
Bei den herkömmlichen Methoden der clientseitigen Darstellung bist du darauf angewiesen, dass der Browser JavaScript ausführt, um die anfängliche Benutzeroberfläche anzuzeigen. Dies kann auf Geräten mit begrenzten Ressourcen zu Verzögerungen beim Laden führen. Das Abrufen von Daten über eine Anwendungsprogrammierschnittstelle (API) belastet diese Geräte zusätzlich, was zu Verzögerungen bei der Anzeige von Inhalten führen und die Benutzerinteraktion beeinträchtigen kann.
Serverkomponenten bieten eine Lösung für diese Probleme, indem sie das Rendern von Komponenten auf dem Server ermöglichen. Dadurch kann der Server die Komponenten an die Client-Seite streamen, was die performance und die Datenabrufprozesse verbessert, da die gesamte Verarbeitung auf dem Server und nicht auf den Geräten der Nutzer stattfindet.
In diesem Artikel erfährst du, wie sich die Rendering-Methoden von React im Laufe der Zeit weiterentwickelt haben, sowie welche Nachteile die Verwendung von React Suspense und serverseitigem Rendering (SSR) mit sich bringt. Außerdem lernst du React Server Components (RSCs) kennen und erfährst, wie sie diese Probleme lösen.
Bevor wir uns mit RSCs beschäftigen, ist es hilfreich, frühere Rendering-Strategien wie React Suspense und SSR zu verstehen.
React Suspense wurde eingeführt, um das asynchrone Rendering in React-Anwendungen zu handhaben. Es ermöglicht Komponenten, das Rendering „auszusetzen“, bis bestimmte Bedingungen erfüllt sind, wie zum Beispiel das Abrufen von Daten oder Code-Splitting. Hier sind einige der Vorteile von Suspense:
React.lazy“, um Code-Splitting zu ermöglichen und die performance zu verbessern, indem Komponenten erst dann geladen werden, wenn sie benötigt werden.React Suspense hat jedoch einige Einschränkungen, die du beim Skalieren deiner Anwendung beachten solltest:
Suspense` und `ErrorBoundary` umschließen musst, was zu sich wiederholendem Code führt und es schwieriger macht, alles konsistent und wartbar zu halten, wenn deine App wächst.Beim SSR werden React-Komponenten auf dem Server gerendert, und anschließend wird der vollständig generierte HTML-Code zur Anzeige an den Client gesendet. Im Gegensatz dazu werden bei RSCs einzelne Komponenten gerendert, sobald sie bereit sind, anstatt wie beim SSR darauf zu warten, dass die gesamte Anwendung geladen ist. Dieser Ansatz hat mehrere Vorteile:
SSR hat jedoch auch Einschränkungen, die es zu beachten gilt:
RSCs sind ein neuer Komponententyp in React, der im Gegensatz zu herkömmlichen Komponenten, die auf der Client-Seite laufen, serverseitig arbeitet. Sie helfen dabei, die mit Suspense und herkömmlichem SSR verbundenen Probleme zu lösen, indem sie es ermöglichen, Komponenten zu verarbeiten und als HTML vom Server zum Client zu streamen. RSCs übernehmen zudem den Datenabruf auf dem Server und stellen so sicher, dass vertrauliche Informationen wie API-Schlüssel dem Client nicht offengelegt werden.
RSCs bieten einige wesentliche Vorteile:
Im Vergleich zu clientseitigen Komponenten handhaben RSCs Ausführung, Datenverwaltung und performance auf unterschiedliche Weise.
Herkömmliche Komponenten laufen im Browser (clientseitig), wo JavaScript benötigt wird, um die Benutzeroberfläche (UI) anzuzeigen. RSCs laufen auf dem Server, indem sie vorgerendertes HTML an das Client-Gerät senden, anstatt alles lokal zu verarbeiten. Dieser Ansatz entlastet das Gerät des Nutzers und verbessert die Ladegeschwindigkeit. Die serverseitige Verarbeitung von Layouts und statischen Inhalten eignet sich zudem ideal für nicht-interaktive oder datengesteuerte Komponenten. Client-Komponenten können in RSCs verschachtelt werden, wenn Interaktivität erforderlich ist, beispielsweise bei Schaltflächen oder Formularen, während sensible Daten sicher auf dem Server verbleiben.
Herkömmliche Komponenten können die Größe des clientseitigen JavaScript-Bundles erhöhen, was zu einer langsameren Performance der App führen könnte. RSCs vergrößern das Paket auf dem Client nicht, da sie serverseitig arbeiten, was zu weniger Downloads und schnelleren Ladezeiten führt. Du kannst RSCs auch nutzen, um das Caching zu verbessern. Serverseitig gerenderte Inhalte lassen sich leichter zwischenspeichern, was die Antwortzeiten für häufig abgerufene Daten – wie beliebte Produkte in einem Online-Shop – beschleunigt, ohne die Datenbank wiederholt abfragen zu müssen.
Der einfachste Weg, RSCs in der Praxis zu nutzen, ist über den Next.js App Router, der integrierte Unterstützung für React Server Components bietet, ohne dass eine manuelle Webpack- oder Babel-Konfiguration erforderlich ist.
Beachte, dass die Beispiele zum Programmieren in diesem Abschnitt Next.js 15 mit React 19 verwenden.
Stelle sicher, dass du Node.js 22 (aktuelle LTS-Version) installiert hast, und erstelle dann ein neues Next.js-Projekt:
npx create-next-app@latest your-app
cd [your-app]Wähle bei der Aufforderung die Option „App Router“ aus. Das ist wichtig, da RSCs nur im App Router verfügbar sind, nicht im veralteten Pages Router.
Im Next.js App Router ist jede Komponente standardmäßig eine Serverkomponente. Erstelle eine Datei unter app/components/UserList.jsx:
// app/components/UserList.jsx
// This is a server component by default - no directive needed
async function UserList() {
// Data fetching happens on the server
// API keys and sensitive data never reach the client
const users = [
{ id: 1, name: "John Doe" },
{ id: 2, name: "Jane Smith" },
{ id: 3, name: "Alice Johnson" },
];
return (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
export default UserList;
Um clientseitige Interaktivität hinzuzufügen, musst du eine Komponente explizit mit der Anweisung „use client“ kennzeichnen. Erstelle eine Datei unter app/components/Counter.jsx:
// app/components/Counter.jsx
"use client"; // This directive marks it as a client component
import { useState } from "react";
function Counter({ initialCount }) {
const [count, setCount] = useState(initialCount);
return (
<div>
<button onClick={() => setCount((prev) => prev + 1)}>
Increment
</button>
<p>Count: {count}</p>
</div>
);
}
export default Counter;Aktualisiere nun app/page.jsx, um beide Komponenten zu kombinieren:
// app/page.jsx
// This is a server component - it can import both server and client components
import UserList from "./components/UserList";
import Counter from "./components/Counter";
export default function Page() {
return (
<div>
<h1>Users</h1>
<UserList /> {/* Rendered on the server */}
<Counter initialCount={50} /> {/* Interactive, runs on the client */}
</div>
);
}Starte den Entwicklungsserver:
npm run dev
Deine App läuft unter http://localhost:3000. Die UserList-Komponente wird auf dem Server gerendert und überträgt HTML an den Client, während die Counter-Komponente im Browser geladen wird und die Interaktivität lokal abwickelt.
Der wesentliche Unterschied zu herkömmlichem React besteht darin, dass „UserList“ kein JavaScript an den Browser sendet – nur HTML. Das reduziert die Größe deines clientseitigen Bundles und verbessert automatisch die performance.
Da RSCs den Großteil der Darstellung auf dem Server übernehmen, kann die Verlagerung möglichst vieler Darstellungsschritte deiner App auf den Server die performance erheblich verbessern, während interaktive Features bei Bedarf erhalten bleiben. Im Folgenden findest du einige Best Practices, die dir dabei helfen können, dies zu erreichen und die Geschwindigkeit, Flexibilität und Verwaltbarkeit deiner Anwendung mit RSCs zu verbessern.
Erstens: Nutze RSCs, um Daten aus APIs oder Datenbanken abzurufen. Wenn du Daten bereits auf dem Server abgerufen hast, rufe sie nicht noch einmal auf dem Client ab. Wenn du beispielsweise Benutzerdaten auf dem Server lädst und an den Client weiterleitest, ist kein zweiter API-Aufruf auf der Client-Seite erforderlich, es sei denn, die Daten ändern sich.
Das Programmieren des Codes in kleine Teile und das selektive Laden der benötigten Skripte mithilfe von Tools wie Vite oder Webpack kann helfen, die Ladezeiten zu verbessern. Erstelle Komponenten, die in deiner gesamten App wiederverwendet werden können. Wenn zum Beispiel mehrere Seiten eine Liste von Nutzern anzeigen müssen, erstelle eine „UserList“-Komponente, die überall funktioniert.
Schließlich solltest du Serverkomponenten schlank halten, indem du sie ausschließlich auf das Rendern von Daten konzentrierst, da sie im Gegensatz zu Clientkomponenten keinen Zustand verwalten müssen. Konzentriere dich darauf, sie schlank zu gestalten und ausschließlich für das Rendern von Daten zuständig zu machen. Lade nur die Teile einer Seite, die interaktiv sein müssen. Wenn die Seite zum Beispiel größtenteils statisch ist, aber ein Formular oder eine interaktive Schaltfläche enthält, lade nur diese Komponenten.
Obwohl RSCs Vorteile bieten, ist es auch wichtig, die Hindernisse und Grenzen zu verstehen, die mit ihrer Einbindung in dein Projekt einhergehen.
Serverkomponenten können nicht mit Lebenszyklusmethoden wie „useEffect“ oder „useState“ interagieren. Das bedeutet, dass du clientseitige Interaktivität innerhalb von Serverkomponenten nicht verwalten kannst. Wenn beispielsweise ein Formular serverseitig gerendert wird, benötigst du eine Clientkomponente, um Eingabeänderungen in Echtzeit zu verarbeiten.
Wenn du in deinen Projekten sowohl mit client- als auch mit serverseitigen Komponenten arbeitest, ist es wichtig, die Interaktion zwischen diesen beiden Komponententypen in deiner gesamten Anwendung zu regeln, um Probleme zu vermeiden. Wenn deine Anwendung beispielsweise Daten vom Server abruft und den Nutzern ermöglicht, diese Daten lokal auf ihren Geräten zu bearbeiten, kann es zu Problemen kommen, die Daten zwischen dem Server und den clientseitigen Komponenten konsistent zu halten.
Serverkomponenten können nur serialisierbare Props verwenden, was bedeutet, dass du keine Funktionen, Symbole oder komplexe Objekte übergeben kannst, die nicht serialisiert werden können. Wenn du beispielsweise eine Callback-Funktion von einer Serverkomponente an eine Clientkomponente sendest, führt das zu einer Fehlermeldung. Serverseitige Komponenten haben keinen Zugriff auf Browser-APIs wie window, document oder localStorage. Wenn du mit dem DOM interagieren musst, muss das in einer Clientkomponente geschehen.
Wenn das vom Server angezeigte HTML nicht mit den Erwartungen des clientseitigen JavaScripts übereinstimmt, kann dies zu Problemen während des Hydration-Prozesses führen. Beispielsweise können Unterschiede in der Formatierung von Datumsangaben auf dem Server im Vergleich zum Client zu subtilen Abweichungen führen. Hydration-Abweichungen können schwer zu beheben sein, da die Ursache nicht immer offensichtlich ist.
Manche Bibliotheken von Drittanbietern funktionieren möglicherweise nicht gut mit RSCs, insbesondere solche, die stark von clientseitigen Rendering-Techniken oder browserspezifischen APIs abhängen. Bibliotheken wie beispielsweise „react-router-dom“ erfordern clientseitiges Rendering. Möglicherweise musst du einige Bibliotheken ersetzen oder anpassen, damit sie mit RSCs funktionieren.
Es gibt praktische Lösungen, die du umsetzen kannst, um Konsistenz zu gewährleisten und häufige RSC-Probleme zu beheben.
Verwende Tools zur Zustandsverwaltung, die sowohl auf dem Server als auch auf dem Client funktionieren, wie Redux oder Zustand. Mit diesen Bibliotheken kannst du deinen Zustand zentralisieren, sodass sowohl servergerenderte als auch clientseitige Komponenten auf dieselben Daten zugreifen können. Du könntest zum Beispiel Redux nutzen, um einen globalen Zustand zu speichern, der beiden Seiten der App zur Verfügung steht.
Stelle sicher, dass der Datenfluss zwischen Server und Client durch die gemeinsame Nutzung des Kontexts aufrechterhalten wird. Achte beispielsweise beim Austausch von Benutzerdaten zwischen Server- und Client-Komponenten darauf, dass die Informationen zentral verwaltet werden, um Unstimmigkeiten zu vermeiden.
Erwäge den Einsatz von Entwicklungstools oder Code-Lintern, um nicht serialisierbare Eigenschaften zu identifizieren, die Probleme mit RSCs verursachen könnten. Tools wie ESLint lassen sich beispielsweise so einrichten, dass sie Funktions-Props erkennen, die von serverbasierten Komponenten übertragen werden.
Achte darauf, Komponenten umzugestalten, um sicherzustellen, dass Props serialisiert werden können, und um Probleme mit SSR zu vermeiden. Eine Möglichkeit hierfür ist, bestimmte Vorgänge wie Event-Handler in Client-Komponenten zu verlagern. Wenn du beispielsweise eine Callback-Funktion von einer Server-Komponente übergibst, stelle sicher, dass du den Code so programmierst, dass der Vorgang innerhalb der Client-Komponente stattfindet, in der er verwendet wird.
Um Hydration-Diskrepanzen zu beheben, sind proaktive Test- und Debugging-Techniken erforderlich:
Wenn Software von Drittanbietern nicht wie für die Anforderungen deines Projekts nötig mit den Serverkomponenten zusammenarbeitet, suche nach alternativen Optionen, die serverkompatibel sind. Wenn du für dein Projekt eine open source-Bibliothek verwendest, solltest du darüber nachdenken, etwas zurückzugeben, indem du zu ihrer Entwicklung beiträgst, um auch RSC-Unterstützung einzubauen. Durch deinen Beitrag kannst du deine eigene Anwendung verbessern und gleichzeitig einen positiven Einfluss auf die breitere Community ausüben, die für ihre Arbeit auf dieselbe Bibliothek angewiesen ist.
Indem du diese Herausforderungen mit geeigneten Strategien angehst, kannst du die Einschränkungen von RSCs effizient umgehen und robuste, leistungsstarke Anwendungen entwickeln.
In diesem Artikel haben wir die Rendering-Techniken von React erläutert. Wir haben React Suspense und SSR vorgestellt und einen tiefergehenden Leitfaden zu RSCs bereitgestellt. Du kannst RSCs nutzen, um die performance deiner Anwendung zu verbessern, indem du den Bedarf an clientseitiger JavaScript-Verarbeitung verringerst und das anfängliche Laden der Seiten beschleunigst.
Wenn du RSCs in deinen Projekten ausprobieren möchtest, besteht der erste Schritt darin, die Komponenten in deiner App zu identifizieren, die von SSR profitieren würden. Anschließend kannst du RSCs schrittweise in deinen Code integrieren.
Der Betrieb der Infrastruktur für SSR und Serverkomponenten kann komplex sein. Die Nutzung von Upsun, einer Platform-as-a-Service (PaaS), vereinfacht die Bereitstellung und Skalierung deiner React-Anwendungen. Mit seiner integrierten Node.js-Unterstützung und automatischen Skalierbarkeit hilft dir Upsun dabei, Traffic-Spitzen reibungslos zu bewältigen. Außerdem bietet es Überwachungs- und Sicherheitstools und ermöglicht es dir, mehrere Anwendungen oder Microservices in verschiedenen Sprachen innerhalb eines einzigen Projekts zu verwalten. So kannst du dich ganz auf die Entwicklung deiner React-Anwendung konzentrieren, während Upsun die Kerninfrastruktur übernimmt.