Mục lục

Hydration: Cầu nối giữa HTML Tĩnh và UI Tương tác

Tại sao Next.js cần Hydration? Khám phá quá trình 'hồi sinh' các node HTML khô khan thành một ứng dụng React sống động. Cách xử lý lỗi Hydration Mismatch.

Trong thế giới SSR (Server-Side Rendering) của Next.js, có một khoảnh khắc "ma thuật" gọi là Hydration. Nếu không có nó, trang web của bạn chỉ là một bức ảnh HTML tĩnh, trông thì đẹp nhưng không thể click, không thể nhập liệu.

1. Tại sao cần Hydration?

HTML gửi từ Server về chỉ là những dòng code văn bản. Browser hiểu cách hiển thị màu sắc, font chữ nhưng nó không biết cái button đó có liên kết với hàm handleClick nào trong file JavaScript của bạn.

Hydration (Nhúng nước) là quá trình React chạy trên trình duyệt để "hồi sinh" (attach listeners) vào cấu trúc HTML tĩnh đã có sẵn.

2. Quy trình "Hồi sinh" (The Process)

  1. Snapshot: Server render UI thành HTML và gửi về. Browser hiển thị ngay lập tức (Lợi ích SEO & LCP).
  2. Download: Browser bắt đầu tải các file JavaScript (bundle) chứa logic React.
  3. Double Check: React chạy logic trên Client để tạo ra cây Virtual DOM của chính nó.
  4. Matching: React so sánh cây Virtual DOM vừa tạo với cấu trúc HTML mà Browser đã render từ Server.
  5. Binding: Nếu hai bên khớp nhau, React "cắm" các event handler (onClick, onHover...) vào các element DOM thật.

3. Hydration Mismatch: Cơn ác mộng báo đỏ

Lỗi này xảy ra khi Server Render một kiểu, Client Render một kiểu. React sẽ thông báo: "Prop className did not match..." hoặc "Text content did not match...".

Các nguyên nhân gây "lệch pha":

  • Dữ liệu thời gian: Dùng new Date() (Server render lúc 14h, Client nhận lúc 14h01).
  • Dữ liệu ngẫu nhiên: Math.random().
  • Browser-only APIs: Truy cập window hoặc localStorage trực tiếp trong quá trình render.
tsx:
// ❌ LỖI: Server không có window, Client có window
function Navbar() {
  const width = typeof window !== 'undefined' ? window.innerWidth : 1024;
  return <div>Width: {width}</div>;
}

4. Giải pháp khắc phục (Standard Patterns)

Pattern 1: useEffect Hook (Phổ biến nhất)

Đảm bảo nội dung nhạy cảm chỉ render sau khi đã ở phía Client.

tsx:
function ClientOnly({ children }) {
  const [hasMounted, setHasMounted] = useState(false);

  useEffect(() => {
    setHasMounted(true);
  }, []);

  if (!hasMounted) return null; // Hoặc render Skeleton
  return <>{children}</>;
}

Pattern 2: Suppress Warning (Dùng cho trường hợp bất khả kháng)

Nếu bạn chấp nhận sự khác biệt (như hiển thị timestamp), hãy dùng thuộc tính này.

tsx:
<div suppressHydrationWarning>
  {new Date().toLocaleTimeString()}
</div>

5. Selective Hydration (React 18+)

Trước đây, Hydration là quá trình "tất cả hoặc không gì cả" (All-or-nothing). Với Next.js App Router và Suspense, React thực hiện Selective Hydration:

  • Nó ưu tiên hydrate những phần người dùng đang tương tác (Ví dụ: user đang hover vào Menu).
  • Các phần nặng (Review, Comment) có thể hydrate sau mà không block UI chính.

Kết luận

Hydration là "linh hồn" của ứng dụng SSR. Hiểu rõ nó giúp bạn xử lý triệt để các lỗi render khó chịu và biết cách thiết kế component sao cho tương thích hoàn hảo giữa môi trường Node.js (Server) và Browser (Client).

Quảng cáo
mdhorizontal