DEV Community

丁久
丁久

Posted on • Originally published at dingjiu1989-hue.github.io

React Server Components Guide: Architecture, Patterns, and When to Use RSC in 2026

This article was originally published on AI Study Room. For the full version with working code examples and related articles, visit the original post.

React Server Components Guide: Architecture, Patterns, and When to Use RSC in 2026

React's Biggest Architectural Shift

React Server Components (RSC) represent the most significant change to React's programming model since hooks. They let you render components on the server, stream them to the client, and never send the JavaScript for those components to the browser. The result: smaller bundles, faster page loads, and direct database access from your components. But RSC also introduces a new mental model that confuses even experienced React developers. Here's what you actually need to understand.

The Core Idea: Two Component Types

Server Components (default) Client Components ('use client')
Where they run Server only (at build time or request time)
JavaScript sent to browser Zero (only the rendered output)
Can use async/await, fs, DB queries, secrets, any Node API
Cannot use useState, useEffect, event handlers, browser APIs
Bundles size impact Zero (rendered on server, streamed as HTML/RSC payload)

The mental model shift: In traditional React, every component ships JavaScript to the browser. In RSC, server components are the default — you opt IN to client-side interactivity with 'use client'. This inverts the traditional model where you opt OUT of client-side code with SSR. The result: most of your components (the ones that just render data) send zero JavaScript.

When a Component Should Be Server vs Client

// Server Component (default) — no 'use client' directive
// ✅ Direct database access
// ✅ Async data fetching
// ✅ Keep secrets (API keys, tokens)
// ✅ Large dependencies (stay on server)
// ✅ Render non-interactive content

async function ArticleList() {
    const articles = await db.query('SELECT * FROM articles ORDER BY date DESC');
    return (
        <div>
            {articles.map(a => <ArticleCard key={a.id} article={a} />)}
        </div>
    );
}


// Client Component — must have 'use client' directive
// ✅ Event listeners (onClick, onChange)
// ✅ useState, useReducer, useEffect
// ✅ Browser APIs (localStorage, geolocation, canvas)
// ✅ Custom hooks that use state/effects
// ❌ Direct database access
// ❌ Server-side secrets

'use client';
function LikeButton({ articleId }) {
    const [liked, setLiked] = useState(false);
    return <button onClick={() => setLiked(!liked)}>{liked ? '♥' : '♡'}</button>;
}
Enter fullscreen mode Exit fullscreen mode

The Composition Pattern: Server Shell, Client Islands

The most common RSC pattern: a server component fetches data and wraps client-interactive islands:

// ArticlePage.server.tsx — Server Component
async function ArticlePage({ slug }) {
    const article = await db.article.findUnique({ where: { slug } }); // runs on server
    return (
        <article>
            <h1>{article.title}</h1>
            <div>{article.content}</div>
            <LikeButton articleId={article.id} />      {/* Client Component */}
            <CommentSection articleId={article.id} />   {/* Client Component */}
        </article>
    );
}
Enter fullscreen mode Exit fullscreen mode

Server component (ArticlePage) sends ZERO JavaScript. LikeButton and CommentSection ship their JS. The non-interactive parts (title, content) are rendered on the server and streamed as HTML. This pattern — "server shell, client islands" — is the mental model for RSC architecture.

Streaming and Suspense

RSC works with React Suspense to stream content as it becomes available. The server sends the page shell immediately, then streams in content as data loads:

function ArticlePage({ slug }) {
    return (
        <div>
            <ArticleHeader slug={slug} />              {/* Renders immediately */}
            <Suspense fallback={<Spinner />}>
                <ArticleBody slug={slug} />           {/* Streams when DB query completes */}
            </Suspense>
            <Suspense fallback={<Spinner />}>
                <RelatedArticles slug={slug} />       {/* Streams independently */}
            </Suspense>
        </div>
    );
}
Enter fullscreen mode Exit fullscreen mode

The user sees the header immediately, then the article body streams in, then related articles — all without waiting for the slowest query.

Server Actions: Mutations Without an API Route

RSC also introduces Server Actions — functions that run on the server but can be called directly from client components without creating an API endpoint:

// actions.ts — server file
'use server';
import { revalidatePath } from 'next/cache';

export async function updateArticle(slug: string, data: FormData) {
    const titl
Enter fullscreen mode Exit fullscreen mode

Read the full article on AI Study Room for complete code examples, comparison tables, and related resources.

Found this useful? Check out more developer guides and tool comparisons on AI Study Room.

Top comments (0)