
Virtual DOM là gì? Cách React cập nhật giao diện hiệu quả
Virtual DOM là một lớp trừu tượng trong bộ nhớ mà các framework như React, Preact và Vue dùng để đại diện cho cây DOM thật. Thay vì chạm trực tiếp vào DOM của trình duyệt — thao tác tốn kém và dễ sai — thư viện tạo một bản sao “ảo”, so sánh với bản cũ rồi mới áp dụng thay đổi tối thiểu lên DOM thật. Bài viết này giải thích nguyên lý hoạt động, luồng render và các điểm nên cân nhắc khi dùng.

Vì sao DOM thật lại chậm
DOM là cấu trúc cây đồng nhất: mỗi thẻ HTML là một node, mỗi node có thể có style, thuộc tính, listener. Trình duyệt phải tính lại style, layout và paint cho toàn bộ cây khi có thay đổi. Trong một ứng dụng thực tế, cây DOM có hàng nghìn node; nếu mỗi lần bấm chuột gọi document.getElementById() rồi gán innerHTML, trình duyệt phải dựng lại gần như toàn bộ subtree. Đó là nguồn gốc của hiện tượng “UI giật” và độ trễ cảm nhận rõ rệt trên thiết bị di động.
Ba giai đoạn của một lần render
React chia việc cập nhật giao diện thành ba giai đoạn tách biệt, cho phép bỏ qua nhiều lần render liên tiếp trong cùng một chu kỳ:
- Render (tính toán): hàm component chạy và trả về React Element — một mô tả JSON gọn nhẹ về giao diện, chưa phải DOM.
- Commit (áp dụng): React so sánh cây element mới với cây trước đó, tính danh sách thay đổi tối thiểu rồi ghi vào DOM thật.
- Diff / Reconciliation: thuật toán đối chiếu theo kiểu depth-first, có
keyđể định danh từng node giữa các lần render.
Diff hoạt động như thế nào
Ở mỗi node, React so sánh type và key. Khác loại thì React loại bỏ subtree cũ và dựng lại; cùng loại thì so sánh props và state để quyết định render lại con. Chính vì thuật toán chỉ là phép so sánh cây với chi phí O(n) theo số node, phần đắt nhất — ghi vào DOM thật — luôn được thu hẹp tối đa. Đây là ý tưởng cốt lõi: phí rẻ khi biết là không đổi, phí đắt chỉ khi thực sự đổi.

Ví dụ minh hoạ cơ chế so sánh
Giả sử danh sách công việc hiển thị ba mục. Khi người dùng xoá mục ở giữa, React không xoá cả danh sách và dựng lại. Nó so sánh từng key, giữ nguyên node của mục 1 và mục 3, chỉ cập nhật nội dung text của các node còn lại. Kết quả: thay vì chạm vào hàng trăm node, chỉ vài chữ được ghi lại và hiệu năng gần như không đổi với danh sách dài.
Ưu và nhược điểm của Virtual DOM
| Khía cạnh | Ưu điểm | Nhược điểm |
|---|---|---|
| Hiệu năng | Giảm số thao tác DOM thật | Tốn bộ nhớ cho cây ảo và cây element |
| Tính khai báo | Mô tả giao diện theo dữ liệu, dễ kiểm thử | Cần hiểu vòng đời render để tránh render thừa |
| Render phía máy chủ | Khớp với mô hình SSR, stream tăng tốc lần hiển thị đầu | Không phải mọi trường hợp đều cần lớp trừu tượng |
Khi nào không cần Virtual DOM
Với game, mô phỏng 3D hay hiển thị danh sách hàng nghìn bản ghi cập nhật liên tục, các thư viện render trực tiếp ra DOM hoặc dùng WebGL thường thắng hơn vì bỏ qua được bước diff. Ngược lại, phần lớn ứng dụng quản trị, thương mại điện tử và dashboard có cập nhật theo thao tác người dùng — đúng bài toán Virtual DOM giải quyết.
Kinh nghiệm tối ưu thực tế
- Luôn dùng
keyổn định và duy nhất trong danh sách, tránhindexkhi danh sách có thể thay đổi thứ tự. - Bọc phần tử con bằng
React.memohoặc tách component riêng để cắt chuỗi render. - Đưa tính toán nặng vào
useMemo/useCallback, hoặc chuyển sang Web Worker nếu đo thấy nghẽn ở luồng chính. - Không dùng Virtual DOM cho phần UI tĩnh: HTML tĩnh hay canvas thường rẻ hơn nhiều.
Khi nào Virtual DOM trở thành gánh nặng
Chi phí của Virtual DOM không đến từ thuật toán diff — phần này rất rẻ — mà đến từ chính cây ảo trong bộ nhớ và từ việc tái tạo lại cây element mỗi lần component chạy lại. Với một bảng dữ liệu 10.000 dòng được cập nhật mỗi giây, việc tạo và so sánh hàng chục nghìn node ảo tốn nhiều bộ nhớ hơn việc vẽ trực tiếp. Với các ứng dụng loại này, hãy cân nhắc cửa sổ hoá danh sách (virtualization), thư viện canvas như PixiJS, hoặc các công cụ như Svelte và SolidJS loại bỏ hẳn lớp ảo và biên dịch thẳng thao tác DOM.
Lịch sử hình thành ý tưởng
Khái niệm Virtual DOM xuất hiện từ dự án Mithril của Paul Hunt vào khoảng năm 2011, được xây dựng cho ứng dụng một trang với cấu trúc cập nhật tối thiểu. React tiếp thu ý tưởng này khi phát hành mã nguồn mở năm 2013 và nhanh chóng trở thành tiêu chuẩn mặc định của ngành. Sau đó Preact giữ nguyên API của React nhưng thay thuật toán diff bằng thuật toán đánh dấu theo chiều sâu để giảm thời gian so sánh, còn Svelte và Solid chuyển sang biên dịch tĩnh để loại bỏ hoàn toàn giai đoạn diff lúc chạy. Bạn có thể đọc thêm phần tổng quan tại trang Virtual DOM trên Wikipedia.
Kết luận
Virtual DOM đổi cách chúng ta mô tả giao diện: từ thao tác trực tiếp lên DOM sang khai báo trạng thái và để thư viện tự tính thay đổi tối thiểu. Nó không phải phép màu làm mọi ứng dụng nhanh hơn, nhưng với đa số sản phẩm web, đây là cách cân bằng giữa hiệu năng và tốc độ phát triển tốt nhất.
