React Server Components Explained - Complete Guide
Mahesh Waghmare React Server Components (RSC) represent a fundamental shift in how React applications are built. They enable server-side rendering with zero JavaScript sent to the client for certain components.
Introduction to Server Components
React Server Components allow you to build components that render on the server, reducing client-side JavaScript and improving performance.
Key Benefits:
- Zero JavaScript for server components
- Direct database access
- Better performance
- Smaller bundle sizes
- Improved security
When to Use:
- Data fetching components
- Static content
- Components using server-only APIs
- Large dependencies
How Server Components Work
Server Components render on the server and send serialized results to the client. The client receives the rendered output, not the component code.
Rendering Flow:
- Server renders component
- Serializes result to JSON
- Sends to client
- Client hydrates with minimal JavaScript
Example:
// Server Component (app/page.js in Next.js)
async function ServerComponent() {
const data = await fetch('https://api.example.com/data');
const json = await data.json();
return (
<div>
<h1>{json.title}</h1>
<p>{json.content}</p>
</div>
);
}
Server vs Client Components
Server Components
- Render on server
- No JavaScript sent to client
- Can use async/await
- Direct database access
- Cannot use browser APIs
- Cannot use hooks like useState, useEffect
Client Components
- Render on client
- JavaScript sent to browser
- Can use browser APIs
- Can use React hooks
- Interactive components
- Mark with ‘use client’ directive
Example:
// Server Component
async function ServerList() {
const items = await getItemsFromDatabase();
return (
<ul>
{items.map(item => <li key={item.id}>{item.name}</li>)}
</ul>
);
}
// Client Component
'use client';
function InteractiveButton() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
Clicked {count} times
</button>
);
}
Next.js Implementation
App Router (Next.js 13+)
Server Components are default in App Router:
// app/posts/page.js - Server Component by default
async function PostsPage() {
const posts = await fetch('https://api.example.com/posts').then(r => r.json());
return (
<div>
<h1>Posts</h1>
{posts.map(post => (
<article key={post.id}>
<h2>{post.title}</h2>
<p>{post.excerpt}</p>
</article>
))}
</div>
);
}
Client Component in App Router
// app/components/Counter.js
'use client';
import { useState } from 'react';
export default function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
Mixing Server and Client Components
// app/page.js - Server Component
import ClientCounter from './components/Counter';
import { getServerData } from './lib/server';
export default async function Page() {
const serverData = await getServerData();
return (
<div>
<h1>Server Data: {serverData.title}</h1>
<ClientCounter />
</div>
);
}
Best Practices
- Use Server Components for data fetching
- Use Client Components for interactivity
- Keep Client Components small
- Pass serializable props between components
- Avoid importing Client Components in Server Components
- Use async/await in Server Components
- Handle errors properly
- Optimize data fetching
- Use Suspense for loading states
- Test both server and client rendering
Conclusion
React Server Components enable:
- Better performance
- Smaller bundles
- Direct server access
- Improved security
Key principles:
- Default to Server Components
- Use Client Components only when needed
- Keep components focused
- Optimize data fetching
- Handle errors gracefully
Understanding Server Components is essential for modern React development with Next.js and similar frameworks.
Written by Mahesh Waghmare
I bridge the gap between WordPress architecture and modern React frontends. Currently building tools for the AI era.
Follow on Twitter →