Häufige Fehler bei React Server Components
Sie haben den Next.js App Router übernommen. Server Components sind der Standard. Alles sollte schneller, einfacher und effizienter sein.
Stattdessen debuggen Sie um 2 Uhr morgens Hydration-Mismatches, fragen sich, warum Ihr Bundle gewachsen ist, und zweifeln daran, ob die 'use client'-Direktive dort hingehört, wo Sie sie platziert haben.
React Server Components stellen einen grundlegenden Wandel in der Funktionsweise von React-Anwendungen dar. Die Server/Client-Grenze ist nicht mehr nur eine Deployment-Überlegung – sie ist eine architektonische Entscheidung, die Sie bei jeder Komponente treffen. Wenn Sie dies falsch machen, führt das zu subtilen Bugs, Performance-Regressionen und Code, der gegen das Framework arbeitet, anstatt es zu nutzen.
Dieser Artikel behandelt die häufigsten Fehler bei React Server Components, die ich in Produktions-Codebasen gesehen habe, und wie Sie diese vermeiden können.
Wichtigste Erkenntnisse
- Server Components sind der Standard im Next.js App Router – platzieren Sie
'use client'so weit unten im Component-Tree wie möglich, um die Bundle-Größe zu minimieren. - Verwenden Sie das
server-only-Package, um die versehentliche Offenlegung von sensiblem Server-Code im Client-Bundle zu verhindern. - Konvertieren Sie immer nicht-serialisierbare Werte (wie Funktionen und Klasseninstanzen), bevor Sie sie von Server- zu Client Components übergeben.
- Server Actions (
'use server') sind RPC-artige Endpunkte, keine Server Components – validieren Sie alle Eingaben und vertrauen Sie niemals Client-Daten. - Seien Sie explizit bezüglich des Caching-Verhaltens mit
revalidateodercache: 'no-store', da sich die Next.js-Standardwerte über verschiedene Versionen hinweg geändert haben.
Server vs. Client Components verstehen
Bevor wir uns den Fallstricken widmen, lassen Sie uns die Grundlagen klären. Im App Router sind Komponenten standardmäßig Server Components. Sie laufen auf dem Server, haben keinen Zugriff auf Browser-APIs und liefern null JavaScript an den Client.
Client Components erfordern die 'use client'-Direktive. Sie können Hooks wie useState und useEffect verwenden, auf Browser-APIs zugreifen und Benutzerinteraktionen verarbeiten.
Die Grenze zwischen ihnen ist der Ort, an dem die meisten Fehler passieren.
Übermäßige Verwendung der ‘use client’-Direktive
Der häufigste Fehler beim Next.js App Router mit RSC ist es, zu früh zu 'use client' zu greifen. Eine Komponente benötigt useState? Markieren Sie sie als Client Component. Brauchen Sie einen onClick-Handler? Client Component.
Das Problem: 'use client' erzeugt eine Grenze. Alles, was diese Komponente importiert, wird Teil des Client-Bundles, selbst wenn diese Imports auf dem Server hätten bleiben können.
// ❌ Die gesamte Seite wird zu einer Client Component
'use client'
import { useState } from 'react'
export default function ProductPage({ product }) {
const [quantity, setQuantity] = useState(1)
return (
<div>
<ProductDetails product={product} />
<ProductReviews productId={product.id} />
<QuantitySelector value={quantity} onChange={setQuantity} />
</div>
)
}
// ✅ Nur das interaktive Element ist eine Client Component
import ProductDetails from './ProductDetails'
import ProductReviews from './ProductReviews'
import QuantitySelector from './QuantitySelector'
export default function ProductPage({ product }) {
return (
<div>
<ProductDetails product={product} />
<ProductReviews productId={product.id} />
<QuantitySelector /> {/* Dies ist die einzige Client Component */}
</div>
)
}
Platzieren Sie 'use client' so weit unten im Component-Tree wie möglich. Isolieren Sie Interaktivität in die kleinsten Komponenten, die sie benötigen.
Import von Server-Only-Code in Client Components
Wenn eine Client Component ein Modul importiert, wird dieses gesamte Modul (und seine Abhängigkeiten) an den Browser ausgeliefert. Importieren Sie einen Datenbank-Client oder eine Datei, die Umgebungs-Secrets liest? Sie haben gerade Server-Only-Code dem Client-Graph offengelegt.
// lib/db.js
import 'server-only' // Fügen Sie dies hinzu, um versehentliche Client-Imports zu verhindern
export async function getUsers() {
return db.query('SELECT * FROM users')
}
Das server-only-Package (bereitgestellt von Next.js) verursacht einen Build-Fehler, wenn das Modul jemals in eine Client Component importiert wird. Verwenden Sie es für jeden Code, der niemals den Browser erreichen darf.
Discover how at OpenReplay.com.
Übergabe nicht-serialisierbarer Werte über die Grenze
Server Components übergeben Props an Client Components durch Serialisierung. Funktionen, Klasseninstanzen, Map und Set können diese Grenze nicht überschreiten.
// ❌ Klasseninstanzen sind nicht serialisierbar
export default async function UserProfile({ userId }) {
const user = await getUser(userId)
return <ClientProfile user={user} /> // user ist eine Klasseninstanz
}
// ✅ In ein einfaches Objekt konvertieren
export default async function UserProfile({ userId }) {
const user = await getUser(userId)
return (
<ClientProfile
user={{
id: user.id,
name: user.name,
createdAt: user.createdAt.toISOString()
}}
/>
)
}
Missverständnisse bei React Server Actions
Die 'use server'-Direktive markiert Funktionen als Server Actions – vom Client aufrufbar, aber auf dem Server ausgeführt. Sie macht eine Komponente nicht zu einer Server Component. Server Components benötigen keine Direktive, da sie der Standard sind.
// Dies ist eine Server Action, keine Server Component
async function submitForm(formData) {
'use server'
await db.insert({ email: formData.get('email') })
}
Server Actions sind effektiv RPC-artige Endpunkte. Behandeln Sie sie wie API-Routes: Validieren Sie Eingaben, behandeln Sie Fehler und vertrauen Sie niemals Client-Daten.
Ignorieren des RSC-Caching-Modells
Das Caching-Verhalten von Next.js hat sich erheblich weiterentwickelt. Gehen Sie nicht davon aus, dass fetch-Aufrufe standardmäßig gecacht werden – dies variiert je nach Next.js-Version, Route-Segment-Konfiguration und Runtime-Einstellungen. Seien Sie explizit bezüglich der Datenaktualität.
// Seien Sie explizit über Caching-Absichten
const data = await fetch(url, {
next: { revalidate: 3600 } // Cache für 1 Stunde
})
// Oder komplett deaktivieren
const data = await fetch(url, { cache: 'no-store' })
Verwenden Sie revalidatePath() und revalidateTag() in Server Actions, um gecachte Daten nach Mutationen zu invalidieren. Das RSC-Caching-Modell erfordert bewusste Entscheidungen über die Datenaktualität.
Fazit
React Server Components belohnen sorgfältiges Nachdenken darüber, wo Code ausgeführt wird. Standardmäßig Server Components verwenden. Client-Grenzen nach unten verschieben. Daten an der Grenze serialisieren. Server-Action-Eingaben validieren. Explizit beim Caching sein.
Das mentale Modell braucht Zeit, um verinnerlicht zu werden, aber die Vorteile – kleinere Bundles, schnellere Ladezeiten, einfacheres Data-Fetching – sind die Investition wert.
FAQs
Teilweise. Server Components können keine State- oder Effect-Hooks wie useState oder useEffect verwenden, da sie nur auf dem Server laufen. Hooks wie useContext werden jedoch unterstützt. Wenn Ihre Komponente State, Effects oder Browser-APIs benötigt, müssen Sie die use client-Direktive hinzufügen, um sie zu einer Client Component zu machen. Halten Sie diese interaktiven Teile so klein und isoliert wie möglich.
Fragen Sie sich, ob die Komponente Interaktivität, Browser-APIs oder React-Hooks wie useState oder useEffect benötigt. Falls ja, muss es eine Client Component sein. Wenn sie nur Daten rendert oder aus einer Datenbank abruft, behalten Sie sie als Server Component. Im Zweifelsfall beginnen Sie mit einer Server Component und fügen Sie use client nur hinzu, wenn der Build oder die Runtime dies explizit erfordert.
Die häufigste Ursache ist die zu hohe Platzierung von use client in Ihrem Component-Tree. Wenn ein Parent zu einer Client Component wird, werden alle ihre Imports Teil des Client-Bundles. Überprüfen Sie Ihre use client-Direktiven und verschieben Sie sie zu den kleinsten interaktiven Komponenten. Prüfen Sie auch auf versehentliche Imports von Server-Only-Bibliotheken im Client-Code.
Die use client-Direktive markiert eine Komponente zur Ausführung im Browser mit Zugriff auf Hooks und Browser-APIs. Die use server-Direktive markiert eine Funktion als Server Action, die vom Client aufrufbar ist, aber auf dem Server ausgeführt wird. Server Components benötigen überhaupt keine Direktive, da sie im Next.js App Router der Standard sind.
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.