EN/CH Mode
BRUCE_FE React Interview Notes - Server Components & Hydration
Deep dive into React Server Components concepts, Hydration principles, and use cases. Understand how RSC changes frontend development, improves performance and user experience, and differs from traditional client-side rendering.
EN/CH Mode

Lazy to read articles? Then watch videos!
What are React Server Components?
React Server Components (RSC) is a new feature from the React team that allows your React components to run on the server instead of just in the browser.
Simply put, RSC lets you decide: 'This component should run on the server' or 'This component should run in the browser', combining the advantages of both.
Traditional React vs Server Components
Traditional React
- 1. All components run in the browser
- 2. Need to download all JS code
- 3. Data fetching requires additional API requests
Rendering Process
Server Components
- 1. Some components run on the server
- 2. Only download needed JS code
- 3. Can fetch data directly on the server
Rendering Process
Note: Server Components are not the same as SSR! SSR renders the entire application to HTML on the server and then "hydrates" it in the browser to become interactive; RSC can render only specific components on the server, reducing browser overhead.
How to Use Server Components
How Server Components and Client Components Work
Architecture Comparison
Server Components
在服务器上渲染
直接访问服务器资源
(数据库、文件系统等)
输出静态HTML和引用
Client Components
Rendered in browser
Can use React Hooks
(useState, useEffect, etc.)
Handle user interactions
Final Content Received by Browser
Rendered HTML content + reference placeholders
JavaScript code + initial state
RSC Payload (specially formatted JSON) + JavaScript Bundle (Client Components only)
Real Example: Non-interactive Leaderboard
Here's a typical Server Component use case - a purely display data leaderboard:
// LeaderboardPage.js (Server Component)
// Note: No "use client" directive, defaults to Server Component
import { getTopUsers } from '@/lib/database';
// This async component fetches data directly on the server
export default async function LeaderboardPage() {
// Direct database access, no API calls needed
const topUsers = await getTopUsers(50);
return (
<div className="leaderboard">
<h1>Weekly Leaderboard</h1>
<div className="leaderboard-list">
{topUsers.map((user, index) => (
<div key={user.id} className="leaderboard-item">
<div className="rank">{index + 1}</div>
<div className="user-avatar">
<img src={user.avatar} alt={user.name} />
</div>
<div className="user-info">
<h3>{user.name}</h3>
<p>{user.points} points</p>
</div>
</div>
))}
</div>
</div>
);
}Advantages:
- 1. Data fetched directly on server, no extra API requests needed
- 2. No loading state handling needed, server has completed rendering
- 3. Browser doesn't need to download JavaScript code for data fetching and processing
- 4. Since there's no interactivity, the entire component can remain a Server Component
- 5. SEO friendly, search engines can directly crawl complete content
Leaderboard Rendering Process Diagram
Server Component vs Client Component Leaderboard Rendering Process
Server Component
User requests page
Server executes React component
Direct access to database/file system
Server renders HTML
Returns complete HTML
Single network request
Browser displays content immediately
No need to wait for additional requests
Client Component
User requests page
Server returns basic HTML and JS
Needs to download large JS code
Browser downloads and executes JS
Consumes client resources
Component sends API requests for data
Additional network request delay
Renders UI after data fetching
Needs to handle loading and error states
Mode Comparison
Server Component Advantages
- 1. Reduced network requests
- 2. Reduced client-side JS size
- 3. No loading state handling needed
- 4. Direct backend resource access
- 5. SEO friendly
- 6. Faster initial content display
Client Component Disadvantages
- 1. Requires additional API requests
- 2. Larger JS bundle size
- 3. Loading state handling required
- 4. Additional error handling needed
- 5. Slower initial content display
- 6. Not SEO friendly
Main Benefits of Using React Server Components
1. Reduce JavaScript Download Size
Server component code is not sent to the browser, only the rendering result is sent, significantly reducing the amount of JS users need to download.
For example:
For components using large date processing libraries, after server rendering, the browser doesn't need to download that library
2. Direct Access to Server Resources
Can directly access databases or file systems within components, no extra API needed.
// Server component can directly query database
async function ProductList() {
// Fetch data directly from database
const products = await db.query('SELECT * FROM products');
return (
<div>
{products.map(product => (
<ProductCard key={product.id} product={product} />
))}
</div>
);
}3. Faster Page Loading
Reduce JS download size and eliminate API requests, making page loading and interaction faster.
4. Preserve Client State
When updating server components, client component state is not reset, making the experience smoother.
Server Components vs Client Components
| Feature | Server Components | Client Components |
|---|---|---|
| Rendering Location | Server | Client Browser |
| Can use useState/useEffect | ❌ No | ✅ Yes |
| Can access server resources | ✅ Yes | ❌ No |
| Event Handling | ❌ Not Supported | ✅ Supported |
| Impact on Bundle Size | No increase in client bundle size | Increases client bundle size |
| File Naming (Next.js) | Default format | "use client" directive |
Using Server Components and Client Components Together (Next.js 13+)
'Leaf' Pattern
Push interactive components (Client Components) to leaf positions as much as possible, keeping outer containers as Server Components.
// ❌ Poor practice
"use client"; // Entire page is a Client Component
export default function Page() {
return (
<Layout>
<Header />
<Main />
<Footer />
</Layout>
);
}
// ✅ Optimized approach
// page.js (default Server Component)
export default function Page() {
return (
<Layout>
<Header />
<Main>
<InteractiveWidget /> {/* Client Component only where needed */}
</Main>
<Footer />
</Layout>
);
}Separating Data Fetching and Rendering
Fetch data in Server Components, then pass the data as props to Client Components.
// Server Component handles data fetching
async function ProductPage({ productId }) {
// Fetch data on the server
const product = await fetchProduct(productId);
const inventory = await fetchInventory(productId);
// Pass data to client component for interaction
return (
<div>
<ProductInfo product={product} />
<AddToCartButton
productId={productId}
inStock={inventory.inStock}
/>
</div>
);
}
// Client Component handles interaction
"use client";
function AddToCartButton({ productId, inStock }) {
// Client-side state and event handling
const [isAdding, setIsAdding] = useState(false);
if (!inStock) {
return <button disabled>Out of Stock</button>;
}
return (
<button
onClick={async () => {
setIsAdding(true);
await addToCart(productId);
setIsAdding(false);
}}
>
{isAdding ? 'Adding...' : 'Add to Cart'}
</button>
);
}Deep Dive into React Hydration Process
Hydration is the crucial process where React 'brings life' to static HTML, transforming it into a dynamic, interactive application.
🔄 Complete Hydration Process:
1. Server-side Rendering
Generate initial HTML & data
2. HTML Delivery
User sees static content
3. JS Loading & Parsing
React code begins execution
4. Event Listeners Attachment
Bind all interactions
5. State Initialization
Set up initial React state
6. Fully Interactive
Application fully usable
⚠️ Common Issues During Hydration
1. Content Mismatch Issues
// 🚫 Problem: Server and client render mismatch
function UserGreeting() {
// Different greetings on server and client
const greeting = new Date().getHours() < 12 ? 'Good Morning' : 'Good Afternoon';
return <h1>{greeting}</h1>;
}
// ✅ Solution: Ensure consistency
function UserGreeting() {
const [greeting, setGreeting] = useState('Hello'); // Default value
useEffect(() => {
// Update greeting only on client
const hour = new Date().getHours();
setGreeting(hour < 12 ? 'Good Morning' : 'Good Afternoon');
}, []);
return <h1>{greeting}</h1>;
}2. Performance Issues During Hydration
- Large JavaScript bundles causing hydration delays
- Complex calculations running too early affecting interactivity
- Improperly handled async data loading
🔥 Common Interview Questions
(1) What are React Server Components? How do they differ from traditional SSR?
Answer: React Server Components (RSC) allow certain components to run only on the server, reducing browser load.
Traditional SSR
1. Entire application renders on server
2. All JS is sent to browser
3. Browser needs to hydrate entire application
4. Subsequent updates all on browser side
Server Components
1. Can choose which components render on server
2. Only send JS for Client Components
3. Browser only hydrates Client Components
4. Can continuously fetch updates from server
Imagine SSR is like sending a photo to a friend who then needs to download editing software; while RSC is like sending the edited photo directly, ready for your friend to post on Instagram.
(2) When should you use Server Components and Client Components?
Server Components are suitable for:
- Pure display content, no interaction needs, direct database access required
- Using large dependency libraries (e.g., date, formatting)
- SEO-important content
// Direct database query
async function Posts() {
const posts = await db.getPosts();
return <PostList posts={posts} />;
}Client Components are suitable for:
- Interfaces requiring user interaction
"use client"; function Counter() { const [count, setCount] = useState(0); return <button onClick={() => setCount(count + 1)}>{count}</button>; } - Using React Hooks (useState, etc.)
- Need browser APIs (localStorage, etc.)
- Forms requiring immediate feedback