← Zurück

React Server Components

Nicht "use client" hinklatschen — VERSTEHEN warum.

❌ Das große Missverständnis

"RSC ist Server-Side Rendering 2.0" — FALSCH.

SSR und RSC sind orthogonal. Sie lösen verschiedene Probleme und können zusammen ODER getrennt verwendet werden.

🧠 Das mentale Modell

SSR (Server-Side Rendering)

React → HTML → Browser

Browser lädt ALLEN Code

Hydration (Event Handlers anbringen)

❌ "Hydration Tax" — alles runterladen

RSC (Server Components)

Server Components → Serialisierter React-Baum

Browser lädt nur Client Component Code

Rekonstruiert React-Baum aus Stream

✅ Kein Code für Server Components im Bundle

Was RSC WIRKLICH ausgibt

RSC gibt kein HTML aus. Es gibt einen serialisierten React-Baum aus:

# RSC Wire Format

M1:{"id":"./ClientComponent.js","chunks":["client1"]}

J0:["$","@1",null,{"children":["$","span",null,{"children":"Hello"}]}]

M Zeilen = Module References (Client Components)

J Zeilen = React Element Trees

@1 = Referenz zu Client Component M1

Warum nicht einfach HTML? Mit dem RSC-Format kann React den Baum rekonstruieren — State bleibt erhalten, Updates sind minimal, es ist ein normales React-Update!

Die Bundler-Magie

Wenn ein Server Component ein Client Component importiert, passiert etwas Interessantes:

Was du schreibst:

import Button from './Button'

Was der Bundler macht:

{
  $$typeof: Symbol(react.module.reference),
  filename: "./Button.client.js",
  name: "default"
}

Nicht die Funktion — nur eine Referenz! Der Server kennt den Client-Code nicht, er weiß nur, dass es ihn gibt.

WARUM keine Hooks in Server Components?

🔄

useState

Wo soll der State leben? Server Components werden einmal ausgeführt und sind dann fertig. Es gibt keinen Browser, der State halten kann.

useEffect

Welchen DOM? Es gibt keinen! Effects laufen nach dem Rendern im Browser — Server Components rendern auf dem Server.

🎯

Das Design

Server Components sind stateless und effectless by design. Nicht als Einschränkung — als Feature!

Props müssen serialisierbar sein

❌ Das geht NICHT

// Server Component
function ServerPage() {
  return (
    <ClientButton 
      onClick={() => alert('hi')}
    />
  )
}

Funktionen sind nicht JSON-serialisierbar!

✅ Das geht

// Client Component
'use client'
function ClientButton() {
  return (
    <button 
      onClick={() => alert('hi')}
    >Click</button>
  )
}

Event Handler leben im Client Component!

Aber: Client Components können Funktionen an andere Client Components übergeben. Die Einschränkung gilt nur an der Server→Client Grenze.

Das Composition Pattern

Client Components können keine Server Components importieren. Aber sie können Server Components als children erhalten!

// ServerPage.server.js
import ClientWrapper from './ClientWrapper'
import ServerContent from './ServerContent'

function ServerPage() {
  return (
    <ClientWrapper>
      <ServerContent />  {/* ✅ Als children! */}
    </ClientWrapper>
  )
}

Der Trick: ServerContent wird vom Server gerendert, bevor es an den Client gesendet wird. Der Client sieht nur den fertigen Output als props.

Suspense & Streaming

RSC unterstützt Streaming. Async Server Components können Suspense Boundaries haben:

1

Server startet Rendering, trifft auf async Component

2

Server sendet Placeholder (Suspense Fallback)

3

Client zeigt Fallback sofort an

4

Async Operation fertig → Server streamt fertigen Content

5

Client ersetzt Placeholder → Kein Flicker!

Wann was verwenden?

Server Component

  • ✅ Data Fetching (DB, APIs)
  • ✅ Große Dependencies (markdown parser, etc.)
  • ✅ Sensitive Logik (API Keys, DB Queries)
  • ✅ Statischer Content

Client Component

  • ✅ Interaktivität (onClick, onChange)
  • ✅ State (useState, useReducer)
  • ✅ Effects (useEffect)
  • ✅ Browser APIs (localStorage, etc.)

✅ Was ich WIRKLICH verstanden habe