React Server Components là gì? Kiến trúc App Router thực tế

React Server Components là gì?

React Server Components (RSC) là mô hình render mới trong React 18+, cho phép các component chạy hoàn toàn trên server, không gửi JavaScript xuống client. Thay vì hydration toàn bộ tree, RSC chỉ gửi HTML và data cần thiết, giảm bundle size, cải thiện TTFB và SEO.

RSC xuất hiện đầu tiên trong Next.js 13 App Router, dần trở thành tiêu chuẩn cho React app hiện đại. Kết hợp với Server Actions, giúp xây dựng full-stack app trong cùng một codebase.

React logo và kiến trúc component-based của React

Khác biệt giữa Server Components và Client Components

Điểm Server Components Client Components
Chạy ở Server only Server + Client (hydration)
Bundle size 0 bytes JS Đóng gói vào client bundle
Truy cập File system, DB, env vars Không truy cập trực tiếp server resource
State Không có useState/useEffect Có đầy đủ hooks và event handlers
Event handlers Không có onClick, onSubmit Có thể xử lý sự kiện client
Third-party libs Chỉ pure functions, không dùng DOM Có thể dùng bất kỳ lib nào

Server Components là “server-only”, Client Components là “client-interactive”.

Sơ đồ so sánh Virtual DOM với real DOM trong React

Cách dùng trong Next.js App Router

Mọi file trong app/ mặc định là Server Component. Để làm Client Component, thêm 'use client' ở đầu file.

// app/page.tsx – Server Component (mặc định)
import { getPosts } from '@/lib/db'

export default async function HomePage() {
  const posts = await getPosts() // Truy cập DB trực tiếp
  return (
    <main>
      <h1>Blog</h1>
      <PostsList posts={posts} /> {/* Client Component */}
    </main>
  )
}

// app/posts-list.tsx – Client Component
'use client'
import { useState } from 'react'

export default function PostsList({ posts }) {
  const [search, setSearch] = useState('')
  
  return (
    <div>
      <input 
        value={search}
        onChange={(e) => setSearch(e.target.value)}
        placeholder="Tìm kiếm bài viết..."
      />
      <ul>
        {posts
          .filter(p => p.title.includes(search))
          .map(p => <li key={p.id}>{p.title}</li>)
        }
      </ul>
    </div>
  )
}

Server Component thực hiện data fetching, truyền props xuống Client Component để tương tác.

Lợi ích thực tế

  1. Giảm JavaScript bundle: Không cần gửi code data fetching, ORM, hoặc libs nặng xuống client.
  2. TTFB nhanh hơn: Server render HTML ngay, không chờ hydration.
  3. SEO tốt hơn: Crawler thấy nội dung đầy đủ mà không cần chạy JS.
  4. An toàn hơn: API keys, DB credentials không rò rỉ ra client bundle.
  5. Streaming SSR: React có thể stream từng RSC khi sẵn sàng.

Giới hạn và best practices

1. Không thể dùng state/hooks

Dùng URL search params hoặc truyền qua props từ parent.

2. Không thể truy cập browser APIs

Không có window, document, localStorage. Dùng cookies qua headers hoặc chuyển sang Client Component.

3. Third-party libs phải pure

Libs như date-fns, lodash OK. Libs phụ thuộc DOM (ví dụ: chart libs) phải dùng trong Client Component.

4. Data fetching pattern

Dùng async/await trực tiếp trong component, không cần useEffect.

Kết luận

React Server Components thay đổi cách chúng ta suy nghĩ về full-stack development. Bằng cách tách biệt rõ ràng giữa logic server và interactivity client, RSC giúp xây dựng ứng dụng React nhanh hơn, an toàn hơn, và dễ bảo trì hơn. Nếu bạn đang dùng Next.js 13+, hãy bắt đầu chuyển đổi gradual từ pages/router tới App Router và sử dụng RSC cho data-heavy components.

Tài liệu tham khảo

Tôi là một lập trình viên IOS. Code chính là IOS nhưng thỉnnh thoảng vẫn đá sang Android hoặc web. Mặc dù không quá thông thạo nhưng tôi sẽ chia sẻ những kiến thức mà mình đã tìm hiểu, áp dụng qua.

Bài viết liên quan

Bevy Engine: Xây dựng game 2D/3D với Rust hiệu năng cao

Bevy là game engine mã nguồn mở được xây dựng bằng Rust, tập trung vào khả năng mở rộng (data-driven) và hiệu năng. Với kiến trúc ECS (Entity Component System)…

Xem thêm

SQLite FTS5 Full-Text Search: Tìm kiếm nội dung trong app không cần server

SQLite FTS5 (Full-Text Search version 5) là công cụ tìm kiếm toàn văn bản tích hợp sẵn trong SQLite, cho phép tìm kiếm nội dung văn bản nhanh chóng mà…

Xem thêm

Golang Concurrency Patterns: Worker Pool, Pipeline, Fan-out/Fan-in thực tế

Golang nổi tiếng với mô hình concurrency “share memory by communicating” thay vì “share memory by locking”. Nhưng pattern thông thường như worker pool, pipeline, fan-out/fan-in không tự động xuất…

Xem thêm
0 0 đánh giá
Article Rating
Theo dõi
Thông báo của
guest
0 Comments
Cũ nhất
Mới nhất Được bỏ phiếu nhiều nhất