React Server Components Deep Dive: When and How to Use Them
Understand React Server Components architecture, learn when to use server vs. client components, and implement common patterns correctly.
React Server Components (RSC) represent the biggest shift in React architecture since hooks. Understanding when and how to use them is crucial for building performant Next.js applications.
The Mental Model
Server Components render on the server and send HTML to the client. They can directly access databases, filesystems, and services without exposing credentials. Client Components are traditional React components that hydrate on the client.
Default Behavior in Next.js App Router
All components in the app directory are Server Components by default. Add "use client" directive to make them Client Components.
Server Components: What You Can Do
// app/users/page.tsx (Server Component)
import { db } from "@/lib/database";
export default async function UsersPage() {
// Direct database access - no API needed!
const users = await db.user.findMany();
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}When to Use Client Components
Use "use client" when you need: useState, useEffect, or other hooks, event handlers (onClick, onChange), browser APIs, or third-party libraries that use client features.
"use client"
import { useState } from "react";
export function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(c => c + 1)}>
Count: {count}
</button>
);
}Composition Patterns
Server Components can import and render Client Components. Client Components cannot import Server Components, but can accept them as children:
// ServerComponent.tsx (Server Component)
import ClientWrapper from "./ClientWrapper";
import ServerContent from "./ServerContent";
export default function Page() {
return (
<ClientWrapper>
<ServerContent /> {/* Rendered on server, passed as children */}
</ClientWrapper>
);
}Data Fetching Patterns
// Parallel data fetching
export default async function Dashboard() {
// These run in parallel
const [users, orders, analytics] = await Promise.all([
getUsers(),
getOrders(),
getAnalytics(),
]);
return <DashboardView users={users} orders={orders} analytics={analytics} />;
}Streaming with Suspense
import { Suspense } from "react";
export default function Page() {
return (
<div>
<h1>Dashboard</h1>
<Suspense fallback={<Skeleton />}>
<SlowComponent />
</Suspense>
</div>
);
}Common Mistakes to Avoid
1. Don't add "use client" unnecessarily - it increases bundle size.
2. Don't try to use hooks in Server Components.
3. Don't pass non-serializable props (functions, classes) from Server to Client Components.
4. Don't fetch data in Client Components when Server Components can do it.
Performance Benefits
Server Components reduce JavaScript bundle size, enable streaming, eliminate client-side data fetching waterfalls, and keep sensitive logic on the server.
NyxaLabs React Development
We build high-performance React applications using modern patterns including Server Components. Our team stays current with the React ecosystem to deliver optimal solutions. Let's discuss your React project.