BRUCE_FEBRUCE_FE

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.

影片縮圖

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: Send React code bundle
Browser: Download JS bundle
Browser: Execute React code
Browser: Send API requests for data
Browser: Render UI

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

Server: Execute Server Components
Server: Fetch data directly
Server: Generate HTML/UI description
Server: Only send JS for Client Components
Browser: Receive HTML (no JS overhead)
Browser: Only handle interactive components

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和引用

No JavaScript transmitted to client

Client Components

Rendered in browser

Can use React Hooks

(useState, useEffect, etc.)

Handle user interactions

JavaScript code transmitted to client

Final Content Received by Browser

Server Components:

Rendered HTML content + reference placeholders

Client Components:

JavaScript code + initial state

Final Result:

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
1

User requests page

2

Server executes React component

Direct access to database/file system

3

Server renders HTML

4

Returns complete HTML

Single network request

5

Browser displays content immediately

No need to wait for additional requests

Client Component
1

User requests page

2

Server returns basic HTML and JS

Needs to download large JS code

3

Browser downloads and executes JS

Consumes client resources

4

Component sends API requests for data

Additional network request delay

5

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

FeatureServer ComponentsClient Components
Rendering LocationServerClient Browser
Can use useState/useEffect❌ No✅ Yes
Can access server resources✅ Yes❌ No
Event Handling❌ Not Supported✅ Supported
Impact on Bundle SizeNo increase in client bundle sizeIncreases 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
  • // Direct database query
    
    async function Posts() {
      const posts = await db.getPosts();
      return <PostList posts={posts} />;
    }
  • Using large dependency libraries (e.g., date, formatting)
  • SEO-important content

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