Mục lục

Quên useEffect đi: Data Fetching chuẩn Next.js 14

Tại sao bạn không nên fetch data bằng useEffect nữa? Hướng dẫn chuyển đổi tư duy sang React Server Components (RSC) để tối ưu SEO và tốc độ.

Nếu bạn đến từ thế giới React truyền thống (SPA), thói quen của bạn chắc chắn là:

  1. Render Component rỗng (Loading Spinner).
  2. useEffect chạy -> Gọi API.
  3. Data về -> setState -> Re-render giao diện.

Trong Next.js App Router, chúng ta vứt bỏ quy trình đó.

1. Tư duy mới: Fetch-then-Render

Với Server Components, chúng ta lấy dữ liệu XONG HẾT ở Server rồi mới gửi HTML về cho Client.

React cũ (SPA)

tsx:
// ❌ Client Component (Rườm rà)
function UserProfile() {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch('/api/user').then(data => {
      setUser(data);
      setLoading(false);
    });
  }, []);

  if (loading) return <Spinner />;
  return <div>{user.name}</div>;
}

Next.js mới (RSC)

tsx:
// ✅ Server Component (Đơn giản, SEO tốt)
export default async function UserProfile() {
  const user = await fetch('https://api.backend.com/user').then(res => res.json());
  
  // Khi dòng này chạy xong, HTML đã có dữ liệu. Client không cần loading.
  return <div>{user.name}</div>;
}

Lợi ích khổng lồ:

  1. Zero Bundle Size: Code fetch data không bị gửi xuống browser.
  2. No Waterfall: Dữ liệu đến cùng lúc với HTML. Không có cảnh "trang web nhảy lung tung" (Layout Shift).
  3. Secure: Access Token và API Key nằm an toàn trên Server.

2. Kỹ thuật Parallel Fetching (Fetch Song Song)

Một lỗi sơ đẳng khi dùng async/await:

tsx:
// ❌ Tuần tự (Waterfall): Tổng thời gian = 3s + 2s = 5s
const user = await getUser(); // Mất 3s
const posts = await getPosts(); // Mất 2s (Phải chờ user xong mới chạy)

Hãy dùng Promise.all để chạy song song:

tsx:
// ✅ Song song: Tổng thời gian = Max(3s, 2s) = 3s
const userData = getUser();
const postsData = getPosts();

// Bắt đầu fetch cả 2 cùng lúc, rồi chờ cả 2 cùng về
const [user, posts] = await Promise.all([userData, postsData]);

3. Request Memoization (Tự động chống trùng lặp)

Bạn lo lắng nếu gọi getUser() ở Header, rồi lại gọi getUser() ở Sidebar thì sẽ bị lãng phí 2 request?

Next.js (mở rộng fetch API) tự động Memoize (ghi nhớ) các request giống nhau trong cùng 1 lần render.

  • Bạn gọi fetch('/api/user') ở 10 component khác nhau.
  • Next.js chỉ gửi ĐÚNG 1 REQUEST thực tế đến Backend.

--> Thoải mái gọi hàm fetch ở bất cứ nơi nào cần dữ liệu, không cần prop drilling (truyền props từ cha xuống con) khổ sở nữa.

Kết luận

useEffect sinh ra để đồng bộ hóa với hệ quả phụ (Side Effect), không phải để fetch data. Hãy để Server làm việc nặng (Fetch Data), để Client làm việc nhẹ (Interactive UI).

Quảng cáo
mdhorizontal