← ~/blog

Server Component và cache trong Next.js 14: giải thích cho người mới

· 6 min read · Next.js

Server Component khác Client Component thế nào, khi nào cần 'use client', và Next.js 14 cache dữ liệu ra sao. Những khái niệm mình thấy người mới hay nhầm nhất.

1. Giới thiệu App Router & Server Components

Từ Next.js 13+, App Router (src/app/) là cách tổ chức route mới, thay cho Pages Router. Mặc định, mọi component trong thư mục app/ đều là React Server Components (RSC).

Tại sao Server Components lại quan trọng?

  • Không làm tăng bundle JS: Các thư viện nặng (như parse markdown, format ngày tháng, query database) được thực thi trên server và không bao giờ bị gom vào bundle JavaScript gửi xuống client.
  • Truy cập Backend trực tiếp: Bạn có thể query PostgreSQL hoặc gọi nội bộ microservice ngay trong component mà không cần qua API route trung gian.
tsx
// src/app/projects/page.tsx
// Đây là Server Component theo mặc định
import { db } from '@/lib/db';

export default async function ProjectsPage() {
  // Query trực tiếp DB tại Server
  const projects = await db.project.findMany({
    orderBy: { createdAt: 'desc' }
  });

  return (
    <div className="grid grid-cols-3 gap-6">
      {projects.map((project) => (
        <div key={project.id} className="p-4 bg-dark-secondary rounded-lg border border-dark-border">
          <h3 className="text-white font-fira">{project.title}</h3>
          <p className="text-text-secondary text-sm mt-2">{project.description}</p>
        </div>
      ))}
    </div>
  );
}

2. Các tầng cache trong Next.js 14

Next.js 14 có bốn tầng cache. Phần này đi qua hai tầng phía server, nơi bạn kiểm soát trực tiếp nhất:

2.1. Request Memoization

Nếu bạn gọi cùng một hàm fetch() với cùng URL nhiều lần trong một chu kỳ render (chẳng hạn ở cả Layout và Page), Next.js sẽ tự động memoize kết quả để chỉ thực hiện 1 network request duy nhất.

2.2. Data Cache (Persistent Server Cache)

Dữ liệu trả về từ fetch được lưu giữ liên tục trên server cho đến khi bạn chủ động revalidate:

tsx
// Tự động làm mới cache sau mỗi 3600 giây (1 giờ) - ISR
const res1 = await fetch('https://api.example.com/products', {
  next: { revalidate: 3600 }
});

// Hoặc sử dụng Tag-based Revalidation cho dữ liệu thời gian thực
const res2 = await fetch('https://api.example.com/cart', {
  next: { tags: ['cart-data'] }
});

3. Khi nào nên dùng 'use client'?

Chỉ thêm chỉ thị 'use client' ở trên cùng của file khi component cần:

  • Dùng các React Hook như useState, useEffect, useRef, useCallback.
  • Gắn các event listener (onClick, onChange).
  • Sử dụng Browser API (window, localStorage, navigator).

Nguyên tắc chung

Để Server Component ở tầng trên cùng (Layout/Page) và đẩy Client Component xuống các component lá nhỏ nhất (Button, Modal, Input).

Bình luận