Virtual DOM từng là nền tảng cốt lõi cho hiệu suất nhanh như chớp của React. Nhưng kể từ phiên bản React 18, mọi thứ đã thay đổi. Virtual DOM vẫn đóng vai trò quan trọng, nhưng không còn là “vương miện” chính nữa. Thay vào đó, các tính năng như rendering đồng thời (concurrent rendering), streaming từ phía server, và server components đang định hình lại cách chúng ta xây dựng giao diện người dùng (UI) hiện đại.
Hãy cùng khám phá điều gì đã thay đổi — và điều đó có ý nghĩa gì với các nhà phát triển.
Ôn lại: Virtual DOM hoạt động thế nào?
Virtual DOM (VDOM) là bản sao trong bộ nhớ của DOM thật. Mỗi lần state thay đổi, React sẽ tạo ra một cây VDOM mới, so sánh (diff) với cây trước đó và tính toán các thao tác tối thiểu cần thiết để cập nhật DOM thật (quá trình reconciliation).
Ví dụ:
function App() { const [count, setCount] = useState(0); return ( <div> <h1>Clicked {count} times</h1> <button onClick={() => setCount(count + 1)}>Click me</button> </div> );
}
Khi setCount
được gọi, React:
- Tạo cây VDOM mới
- So sánh với cây cũ
- Chỉ cập nhật phần thay đổi (
<h1>
trong ví dụ)
Tuy hiệu quả, nhưng quá trình này vẫn tốn CPU nếu cây DOM lớn hoặc cập nhật quá thường xuyên.
Kiến trúc Fiber: Vết nứt đầu tiên trong vương miện VDOM
Virtual DOM ban đầu rất nhanh — nhưng mang tính blocking (chặn). Tất cả cập nhật được xử lý một lần, dễ khiến UI bị đơ trong các ứng dụng phức tạp.
Fiber (giới thiệu từ React 16) là một sự tái cấu trúc lõi để giải quyết vấn đề này. Nó chia nhỏ công việc render thành các đơn vị nhỏ (fiber) có thể tạm dừng, gián đoạn, hoặc ưu tiên.
Fiber hoạt động như sau:
- Chia việc thành các đoạn nhỏ (fiber)
- Có thể tạm ngừng: cho phép các tác vụ gấp như input được ưu tiên
- Ưu tiên công việc: việc quan trọng (click) chạy trước, việc ít quan trọng (lọc danh sách lớn) chạy sau
Fiber là nền móng cho Concurrent Rendering — được hiện thực hóa đầy đủ trong React 18.
React 18: Điều gì thực sự đã thay đổi?
React 18 biến việc render thành bất đồng bộ theo mặc định. Giờ đây, React có thể lên lịch, tạm dừng, và tiếp tục render khi trình duyệt rảnh — nhờ bộ máy Concurrent Rendering.
Điều này không nhằm render nhanh hơn, mà là render thông minh hơn: ưu tiên điều quan trọng, trì hoãn điều không gấp.
Hiểu Concurrent Updates (Cập nhật đồng thời)
Trước React 18, mọi cập nhật đều xử lý đồng bộ. Một tác vụ chậm (như lọc danh sách lớn) có thể làm đơ toàn bộ app — kể cả thao tác nhập liệu.
Giờ đây, với Concurrent Updates, React có thể:
- Ngắt quá trình render ít quan trọng
- Xử lý việc gấp trước (ví dụ: gõ phím)
- Tiếp tục phần render bị tạm dừng khi tài nguyên cho phép
Điều này giúp ứng dụng mượt mà ngay cả khi đang xử lý nặng.
Công cụ mới giúp UI phản hồi tốt hơn
startTransition()
– đánh dấu cập nhật không gấp để React trì hoãnuseDeferredValue()
– hoãn render giá trị nặng để tránh chặn tương tác người dùng- Streaming SSR – gửi HTML thành từng phần từ server
- Server Components – chuyển logic render sang server, giảm tải JS phía client
Những công cụ này giúp bạn xây dựng UI phản hồi tốt bất kể ứng dụng phức tạp thế nào.
Ví dụ: startTransition()
import { useState, startTransition } from 'react'; function Search() { const [input, setInput] = useState(''); const [results, setResults] = useState([]); const handleChange = (e) => { const value = e.target.value; setInput(value); // urgent: update input immediately // non-urgent: update results without blocking UI startTransition(() => { const filtered = someBigList.filter(item => item.includes(value) ); setResults(filtered); }); }; return <input value={input} onChange={handleChange} />;
}
Kết quả: Gõ phím vẫn mượt mà ngay cả khi danh sách lớn — vì việc lọc chạy nền.
Ví dụ: useDeferredValue()
import { useState, useDeferredValue, useMemo } from 'react'; function SearchResults({ query }) { const deferredQuery = useDeferredValue(query); // lower priority // simulate expensive filtering const results = useMemo(() => { return bigList.filter(item => item.includes(deferredQuery) ); }, [deferredQuery]); return <div>{results.length} results found</div>;
}
Kết quả: UI cập nhật ngay khi người dùng gõ, nhưng lọc dữ liệu xảy ra sau — tránh trễ giao diện.
Khi nào Virtual DOM vẫn hữu ích?
- Với các tương tác UI đơn giản: toggle, đếm, biểu mẫu
- Khi dùng routing phía client (SPA có animation)
- Trong ứng dụng nhỏ, nơi không cần SSR/streaming
- Với codebase cũ — không cần di cư toàn bộ
Virtual DOM vẫn mạnh, chỉ là không còn là "ngôi sao" duy nhất.
Điều các Developer cần ghi nhớ: Chuyển đổi tư duy khi thiết kế Component
Với sự thay đổi từ React 18, developer cần vượt ra khỏi tư duy chỉ dùng Virtual DOM. Trước đây, logic chủ yếu nằm ở client, hook chủ yếu để xử lý trạng thái UI. Giờ đây, với concurrent rendering và kiến trúc ưu tiên server, trọng tâm là:
- Ưu tiên các cập nhật theo mức độ khẩn cấp
- Đẩy nhiều việc nhất có thể về server
- Thiết kế component với “ngân sách render” và trải nghiệm người dùng trong đầu
Không còn chỉ là render nhanh — mà là render có chiến lược.
Kết luận: Cân bằng, không phải bỏ rơi
Virtual DOM không biến mất — nó chỉ không còn là trung tâm của hiệu suất. React 18 hướng tới một chiến lược render lai (hybrid): SSR, streaming, và concurrency dẫn đầu — còn Virtual DOM hỗ trợ phía sau.
Render như thể bạn đang ở năm 2025: đồng thời, phản hồi tốt và thông minh từ phía server.
Chúc bạn code vui vẻ ❤️