Teil unserer Performance & Scalability-Serie
Den vollständigen Leitfaden lesenReact 19 Serverkomponenten: Was hat sich geändert und warum
React 19 ist die bedeutendste Veröffentlichung seit Hooks. Serverkomponenten, die als experimentelle Funktion in React 18 begannen, sind jetzt stabil und vollständig in das gleichzeitige Rendering-Modell integriert. Aber die Änderungen gehen weit über die reine Stabilisierung von RSC hinaus – React 19 führt Aktionen, einen neuen use()-Hook, Formularintegration, optimistische Aktualisierungen und Dokumentenmetadatenverwaltung ein, die insgesamt Ihre Einstellung zum Datenfluss in React-Anwendungen verändern.
Dieser Leitfaden konzentriert sich auf die tatsächlichen Änderungen zwischen React 18 und 19, erläutert die architektonischen Gründe für jede Änderung und zeigt die Produktionsmuster, die die alten Ansätze ersetzen.
Wichtige Erkenntnisse
– Serverkomponenten werden nur auf dem Server ausgeführt – sie haben keinen Lebenszyklus, keinen Status und keine Browser-APIs – Der
use()-Hook ersetztawaitin Client-Komponenten zum Konsumieren von Versprechen und Kontext – React 19-Aktionen ersetzen manuelleuseState+fetch-Muster für Formularübermittlungen
useOptimisticermöglicht sofortige UI-Updates vor der ServerbestätigunguseFormStatusgibt Ihnen den Status „Ausstehend“ an, ohne dass Sie Formularkomponenten durchbohren müssen – Mit APIs zum Vorladen von Assets (preload,preinit) können Sie das Laden von Ressourcen aus Komponenten steuern<title>-,<meta>- und<link>-Tags in Komponenten werden automatisch auf<head>angehoben – Serverkomponenten und Clientkomponenten bilden einen Baum – Clientkomponenten können keine Serverkomponenten importieren
Was Serverkomponenten eigentlich sind
Bevor Sie besprechen, was sich geändert hat, klären Sie, was Serverkomponenten sind: Reaktionskomponenten, die ausschließlich auf dem Server gerendert werden und HTML + RSC-Nutzlast erzeugen, die der Client hydratisiert. Sie sind nicht dasselbe wie serverseitig gerenderte Clientkomponenten.
Die wichtigsten Unterschiede:
| Serverkomponenten | Client-Komponenten | |
|---|---|---|
| Läuft auf | Nur Server | Server (erste Darstellung) + Client |
| Kann Haken verwenden | Nein | Ja |
| Kann Browser-APIs verwenden | Nein | Ja |
| Kann auf die Datenbank zugreifen | Ja (direkt) | Nein (über API) |
| Auswirkungen auf die Paketgröße | Null | Ja |
| Kann asynchron sein | Ja | Nein (ohne Spannung) |
// Server Component — async, no hooks, direct DB access
async function UserProfile({ userId }: { userId: string }) {
// Direct database query — no API needed
const user = await db.query.users.findFirst({
where: eq(users.id, userId),
});
return (
<div>
<h1>{user.name}</h1>
{/* Client Component gets data as props */}
<UserActions userId={user.id} role={user.role} />
</div>
);
}
// Client Component — can use hooks, handles interactions
'use client';
function UserActions({ userId, role }: { userId: string; role: string }) {
const [isEditing, setIsEditing] = useState(false);
return (
<div>
<button onClick={() => setIsEditing(true)}>Edit</button>
{isEditing && <EditUserForm userId={userId} />}
</div>
);
}
Reagiere auf 19 Aktionen
Die größte ergonomische Verbesserung in React 19 sind Aktionen – eine standardisierte Methode zur Handhabung asynchroner Vorgänge, die durch Benutzerinteraktionen, insbesondere Formularübermittlungen, ausgelöst werden.
Vor React 19 war die Formularverarbeitung ein sich wiederholendes Muster:
// React 18 — manual state management
function ContactForm() {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [submitting, setSubmitting] = useState(false);
const [error, setError] = useState<string | null>(null);
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
setSubmitting(true);
setError(null);
try {
await createContact({ name, email });
} catch (err) {
setError(err.message);
} finally {
setSubmitting(false);
}
}
return (
<form onSubmit={handleSubmit}>
{/* ... */}
</form>
);
}
React 19 Actions optimieren dies erheblich:
// React 19 — useActionState
'use client';
import { useActionState } from 'react';
async function createContactAction(
prevState: { error?: string },
formData: FormData
) {
'use server'; // Server Action — runs on the server
const name = formData.get('name') as string;
const email = formData.get('email') as string;
try {
await createContact({ name, email });
return { success: true };
} catch (err) {
return { error: err.message };
}
}
function ContactForm() {
const [state, formAction, isPending] = useActionState(
createContactAction,
{}
);
return (
<form action={formAction}>
<input name="name" required />
<input name="email" type="email" required />
{state.error && <p className="text-red-500">{state.error}</p>}
<button type="submit" disabled={isPending}>
{isPending ? 'Submitting...' : 'Submit'}
</button>
</form>
);
}
Der useActionState-Hook verwaltet den ausstehenden Status, die Formulardaten und die Fehlerbehandlung an einem Ort. Die 'use server'-Direktive für die Aktionsfunktion markiert sie als Serveraktion – sie wird auf dem Server ausgeführt, kann direkt auf die Datenbank zugreifen und der Client sieht die Implementierung nie.
Serveraktionen
Serveraktionen sind asynchrone Funktionen mit der Direktive 'use server', die auf dem Server ausgeführt werden, wenn sie vom Client aufgerufen werden. Sie ersetzen API-Routen für die meisten Anwendungsfälle von Datenmutationen:
// app/actions/contacts.ts
'use server';
import { revalidatePath } from 'next/cache';
import { redirect } from 'next/navigation';
import { db } from '@ecosire/db';
import { contacts } from '@ecosire/db/schema';
export async function createContact(formData: FormData) {
const name = formData.get('name') as string;
const email = formData.get('email') as string;
if (!name || !email) {
throw new Error('Name and email are required');
}
await db.insert(contacts).values({
name,
email,
organizationId: await getOrganizationId(), // From session
});
revalidatePath('/dashboard/contacts'); // Invalidate cached page
redirect('/dashboard/contacts'); // Redirect after success
}
Serveraktionen können direkt in form-Elementen verwendet werden:
import { createContact } from '@/app/actions/contacts';
export default function NewContactPage() {
return (
<form action={createContact}>
<input name="name" placeholder="Name" required />
<input name="email" placeholder="Email" type="email" required />
<button type="submit">Create Contact</button>
</form>
);
}
Kein onSubmit-Handler, kein preventDefault(), kein manueller fetch() – das Formular funktioniert einfach.
Der use()-Hook
React 19 führt den use()-Hook zum Verbrauchen von Ressourcen (Promises und Kontext) innerhalb des Renderns ein. Im Gegensatz zu await funktioniert es mit dem Suspense-System von React:
// Before React 19 — had to resolve at the top level
export default async function Page() {
const posts = await getPosts(); // Blocks entire page
return <PostList posts={posts} />;
}
// React 19 — pass a promise, resolve with use()
export default function Page() {
const postsPromise = getPosts(); // Start fetch immediately
return (
<Suspense fallback={<PostsSkeleton />}>
<PostList postsPromise={postsPromise} />
</Suspense>
);
}
// Client Component using use() to consume the promise
'use client';
function PostList({ postsPromise }: { postsPromise: Promise<Post[]> }) {
const posts = use(postsPromise); // Suspends until resolved
return (
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
Der Hook use() ersetzt auch useContext() – er kann Kontext bedingt konsumieren (im Gegensatz zu Hooks kann use() innerhalb von Bedingungen und Schleifen aufgerufen werden):
'use client';
import { use } from 'react';
import { ThemeContext } from '@/contexts/theme';
function Button({ children }: { children: React.ReactNode }) {
const theme = use(ThemeContext); // Can be inside conditions
return (
<button className={theme === 'dark' ? 'bg-gray-800' : 'bg-white'}>
{children}
</button>
);
}
Optimistische Updates mit useOptimistic
useOptimistic bietet sofortiges UI-Feedback, bevor ein Servervorgang abgeschlossen ist, und kehrt automatisch zurück, wenn der Vorgang fehlschlägt:
'use client';
import { useOptimistic, useTransition } from 'react';
interface Like {
id: string;
count: number;
userLiked: boolean;
}
function LikeButton({ postId, initialLikes }: { postId: string; initialLikes: Like }) {
const [likes, setOptimisticLikes] = useOptimistic(
initialLikes,
(state, action: 'like' | 'unlike') => ({
...state,
count: action === 'like' ? state.count + 1 : state.count - 1,
userLiked: action === 'like',
})
);
const [isPending, startTransition] = useTransition();
async function toggleLike() {
const action = likes.userLiked ? 'unlike' : 'like';
startTransition(async () => {
setOptimisticLikes(action); // Instant UI update
// Server operation — if this fails, optimistic state reverts
await togglePostLike(postId, action);
});
}
return (
<button onClick={toggleLike} disabled={isPending}>
{likes.userLiked ? '♥' : '♡'} {likes.count}
</button>
);
}
Das optimistische Update wird sofort angezeigt und dann entweder festgeschrieben (Servererfolg) oder zurückgesetzt (Serverausfall). Benutzer erhalten sofortiges Feedback, ohne auf Netzwerk-Roundtrips warten zu müssen.
Dokumentmetadaten aus Komponenten
Mit React 19 können die Tags <title>, <meta> und <link> in jeder Komponente gerendert werden – sie werden automatisch in das Dokument <head> verschoben:
// Server Component — metadata hoists to <head> automatically
async function BlogPost({ slug }: { slug: string }) {
const post = await getPost(slug);
return (
<article>
<title>{post.title}</title>
<meta name="description" content={post.description} />
<link rel="canonical" href={`https://ecosire.com/blog/${slug}`} />
<h1>{post.title}</h1>
<div>{post.content}</div>
</article>
);
}
Dies funktioniert sowohl in Server- als auch in Client-Komponenten. In Frameworks wie Next.js verwenden Sie weiterhin generateMetadata() für die vollständige Kontrolle über OpenGraph-Tags und Hreflang-Attribute – die native Unterstützung von React 19 ist einfacher. In einfachen Fällen entfällt jedoch die Notwendigkeit von next/head oder ähnlichen Bibliotheken.
APIs zum Laden von Assets
React 19 bietet explizite APIs zum Vorabladen von Ressourcen und ermöglicht Ihnen so eine detaillierte Kontrolle über den Ressourcenladevorgang:
import { preload, preinit, prefetchDNS, preconnect } from 'react-dom';
function BelowFoldSection() {
// When this component renders, preload the hero image for next section
preload('/images/hero-next.webp', { as: 'image' });
// Preinit a script (loads and executes immediately)
preinit('https://cdn.example.com/analytics.js', { as: 'script' });
// DNS prefetch for external resources
prefetchDNS('https://fonts.googleapis.com');
// Establish connection early
preconnect('https://api.ecosire.com');
return <section>{/* content */}</section>;
}
Diese APIs funktionieren korrekt mit dem Rendering-Modell von React – sie stapeln Ressourcenhinweise und geben sie an der optimalen Stelle im Dokument aus, sogar tief im Komponentenbaum.
Häufige Fallstricke und Lösungen
Falle 1: Versuch, Hooks in Serverkomponenten zu verwenden
Serverkomponenten können useState, useEffect, useContext oder andere Hooks nicht verwenden. Wenn Sie diese benötigen, fügen Sie 'use client' zur Komponente hinzu. Der Fehler ist normalerweise: Error: Hooks can only be called inside a function component.
Falle 2: Serverkomponenten aus Clientkomponenten importieren
Client-Komponenten können keine Server-Komponenten importieren (das Gegenteil ist in Ordnung). Dies liegt daran, dass Clientkomponenten in dem Browser ausgeführt werden, in dem keine Serverkomponenten vorhanden sind. Wenn Sie sie zusammenstellen müssen, übergeben Sie Serverkomponenten als children-Requisiten:
// Wrong — Client Component cannot import Server Component
'use client';
import { ServerUserProfile } from './server-user-profile'; // Error
// Correct — pass as children from a Server Component parent
// Parent (Server):
<ClientShell>
<ServerUserProfile userId={userId} />
</ClientShell>
// ClientShell:
'use client';
function ClientShell({ children }: { children: React.ReactNode }) {
return <div className="shell">{children}</div>;
}
Falle 3: Serialisierungsfehler bei der Übergabe von Requisiten vom Server an den Client
Nur JSON-serialisierbare Daten können als Requisiten die Server-Client-Grenze überschreiten. Funktionen, Klasseninstanzen, Map, Set und Dates (als Objekte) können nicht serialisiert werden. Datumsangaben in ISO-Strings konvertieren; Ersetzen Sie Funktionen durch Zeichenfolgenbezeichner.
Falle 4: Serveraktionen validieren Eingaben nicht
Vertrauen Sie niemals vom Client bereitgestellten Daten in Serveraktionen. Validieren Sie immer mit Zod oder ähnlichem, bevor Sie in die Datenbank schreiben:
'use server';
import { z } from 'zod';
const schema = z.object({
name: z.string().min(2).max(255),
email: z.string().email(),
});
export async function createContact(formData: FormData) {
const result = schema.safeParse({
name: formData.get('name'),
email: formData.get('email'),
});
if (!result.success) {
return { error: result.error.flatten().fieldErrors };
}
await db.insert(contacts).values(result.data);
}
Häufig gestellte Fragen
Sind Serverkomponenten außerhalb von Next.js verfügbar?
React-Serverkomponenten sind eine React-Funktion, erfordern jedoch ein Framework zur Verwaltung der Server-Rendering-Infrastruktur – Routing, Bündelung, Streaming. Next.js App Router ist die ausgereifteste Implementierung. Remix-, Astro- und Vite-basierte Setups bieten RSC-Unterstützung. Die Verwendung von RSC ohne Framework erfordert erhebliche kundenspezifische Infrastrukturarbeiten.
Wie vergleichen sich Serveraktionen mit REST-API-Routen?
Serveraktionen sind für Mutationen in Verbindung mit der Benutzeroberfläche einfacher – keine zu verwaltende Endpunkt-URL, kein fetch()-Aufruf zum Schreiben, kein Boilerplate zur Fehlerbehandlung. REST-API-Routen eignen sich besser für Vorgänge, die von außerhalb der Web-App aufgerufen werden (mobile Apps, Webhooks, Integrationen von Drittanbietern), für öffentliche APIs, die eine Dokumentation erfordern, und wenn Sie explizite HTTP-Statuscodes benötigen. Verwenden Sie je nach Anwendungsfall beide in derselben Anwendung.
Welche Auswirkungen haben Serverkomponenten auf die Leistung?
Serverkomponenten reduzieren die Größe des JavaScript-Bundles (Komponentencode wird nie an den Browser gesendet), beseitigen Wasserfälle beim Datenabruf auf der Clientseite und ermöglichen die Streaming-HTML-Bereitstellung über Suspense. Der Nachteil sind die Server-Rechenkosten – das Rendern erfolgt auf Ihren Servern und nicht auf dem Gerät des Clients. Bei datenintensiven Seiten ist dies fast immer ein Nettogewinn.
Kann ich React 18 und React 19 in einer Codebasis mischen?
Der gesamte React-Code wird als React 19 ausgeführt – es gibt keine Versionierung pro Datei. Die Frage ist, ob Ihr vorhandener React 18-Code in React 19 funktioniert. Der meiste React 18-Code funktioniert unverändert. Die wichtigsten bahnbrechenden Änderungen betreffen Refs (jetzt eine reguläre Requisite), die Entfernung von ReactDOM.render und einige Typänderungen in @types/react. Führen Sie die React 19-Codemods für die automatisierte Migration aus.
Wie teste ich Serverkomponenten?
Serverkomponenten können mit der React Testing Library unter Verwendung von async render getestet werden. Testen Sie Serveraktionen als einfache asynchrone Funktionen mit simulierten Datenbankaufrufen. End-to-End-Tests mit Playwright decken die vollständige Integration von Serverkomponente und Clientkomponente ohne spezielle Einrichtung ab – sie testen die endgültige HTML-Ausgabe.
Nächste Schritte
React 19-Serverkomponenten stellen einen grundlegenden Wandel in der Art und Weise dar, wie moderne Webanwendungen erstellt werden. Das Frontend-Team von ECOSIRE hat Produktionsanwendungen auf dieser Architektur erstellt – 249 Seiten mit Serverkomponenten, Serveraktionen und optimistischen Updates, die echte Benutzerworkflows ermöglichen.
Wenn Sie Hilfe bei der Migration von React 18 auf 19 benötigen, eine neue RSC-First-Anwendung entwerfen oder einfach nur Experten für Frontend-Engineering in Ihrem Team benötigen, entdecken Sie unsere Entwicklungsdienste.
Geschrieben von
ECOSIRE Research and Development Team
Entwicklung von Enterprise-Digitalprodukten bei ECOSIRE. Einblicke in Odoo-Integrationen, E-Commerce-Automatisierung und KI-gestützte Geschäftslösungen.
Verwandte Artikel
k6 Load Testing: Stress-Test Your APIs Before Launch
Master k6 load testing for Node.js APIs. Covers virtual user ramp-ups, thresholds, scenarios, HTTP/2, WebSocket testing, Grafana dashboards, and CI integration patterns.
Next.js 16 App Router: Production Patterns and Pitfalls
Production-ready Next.js 16 App Router patterns: server components, caching strategies, metadata API, error boundaries, and performance pitfalls to avoid.
Odoo Performance Tuning: PostgreSQL and Server Optimization
Expert guide to Odoo 19 performance tuning. Covers PostgreSQL configuration, indexing, query optimization, Nginx caching, and server sizing for enterprise deployments.
Mehr aus Performance & Scalability
k6 Load Testing: Stress-Test Your APIs Before Launch
Master k6 load testing for Node.js APIs. Covers virtual user ramp-ups, thresholds, scenarios, HTTP/2, WebSocket testing, Grafana dashboards, and CI integration patterns.
Nginx Production Configuration: SSL, Caching, and Security
Nginx production configuration guide: SSL termination, HTTP/2, caching headers, security headers, rate limiting, reverse proxy setup, and Cloudflare integration patterns.
Odoo Performance Tuning: PostgreSQL and Server Optimization
Expert guide to Odoo 19 performance tuning. Covers PostgreSQL configuration, indexing, query optimization, Nginx caching, and server sizing for enterprise deployments.
Odoo vs Acumatica: Cloud ERP for Growing Businesses
Odoo vs Acumatica compared for 2026: unique pricing models, scalability, manufacturing depth, and which cloud ERP fits your growth trajectory.
Testing and Monitoring AI Agents in Production
A complete guide to testing and monitoring AI agents in production environments. Covers evaluation frameworks, observability, drift detection, and incident response for OpenClaw deployments.
Compliance Monitoring Agents with OpenClaw
Deploy OpenClaw AI agents for continuous compliance monitoring. Automate regulatory checks, policy enforcement, audit trail generation, and compliance reporting.