Virtualization Trong React: Kỹ Thuật Xử Lý 100.000 Dòng Dữ Liệu Không Giật Lag

Bạn có một danh sách 50.000 dòng cần hiển thị trong React. Nếu render tất cả cùng lúc, trình duyệt sẽ phải dựng hàng chục nghìn DOM node — CPU và RAM rên rỉ, UI giật lag nghiêm trọng, và điểm Core Web Vitals lao dốc. Virtualization (hay Windowing) giải quyết bài toán này bằng một nguyên lý đơn giản mà cực kỳ hiệu quả.

virtualizationreact-windowwindowing
Ảnh bìa bài viết: Virtualization Trong React: Kỹ Thuật Xử Lý 100.000 Dòng Dữ Liệu Không Giật Lag
Ảnh đại diện của Trung Vũ Hoàng

Trung Vũ Hoàng

Tác giả

1/4/20263 phút đọc

1. Virtualization Là Gì?

Thay vì render toàn bộ danh sách, Virtualization chỉ render những phần tử đang nằm trong vùng nhìn thấy (viewport) của người dùng — thường là 10–20 phần tử. Khi người dùng cuộn, các phần tử cũ bị xóa khỏi DOM và phần tử mới được chèn vào ngay lập tức.

Kết quả: dù có 100.000 bản ghi trong data, DOM thực tế luôn chỉ có khoảng 10–15 node. Thời gian phản hồi giao diện giảm từ vài giây xuống vài millisecond.

2. Cơ Chế Hoạt Động

Thư viện Virtualization tính toán liên tục vị trí thanh cuộn để xác định phần tử nào cần hiển thị. Nó còn duy trì một vùng đệm (buffer) gồm vài phần tử nằm ngoài viewport — để ngăn "khoảng trắng" xuất hiện khi người dùng cuộn nhanh trước khi hàng mới kịp render.

Về mặt React: Virtualization giảm mạnh số lượng node mà thuật toán reconciliation phải xử lý sau mỗi lần re-render — đây là sự bổ trợ hoàn hảo cho cơ chế Diffing của React.

3. Triển Khai Với react-window

react-window là thư viện tiêu chuẩn cho Virtualization trong React — nhẹ hơn, nhanh hơn so với người tiền nhiệm react-virtualized. Cài đặt:

npm install react-window

Ví dụ danh sách 100.000 phần tử với chiều cao hàng cố định:

import { FixedSizeList as List } from 'react-window';

const Row = ({ index, style }) => (
  <div style={style} className={index % 2 ? 'row-odd' : 'row-even'}>
    Phần tử #{index + 1}
  </div>
);

const MyList = () => (
  <List
    height={500}       // Chiều cao viewport (px)
    itemCount={100000} // Tổng số phần tử
    itemSize={50}      // Chiều cao mỗi hàng (px)
    width="100%"
  >
    {Row}
  </List>
);

Với cấu hình này, chỉ khoảng 10–12 DOM node thực sự tồn tại trong DOM tại bất kỳ thời điểm nào — bất kể itemCount là bao nhiêu.

4. Các Trường Hợp Ứng Dụng Thực Tế

Data Grid hai chiều

Bảng có hàng trăm cột và hàng nghìn dòng — cần ảo hóa cả chiều ngang lẫn chiều dọc. react-window cung cấp FixedSizeGrid cho trường hợp này.

Danh sách tin nhắn (Chat)

Cuộn ngược lên tin nhắn cũ với chiều cao tin nhắn không đều nhau — dùng VariableSizeList kết hợp cache chiều cao đã đo.

Dropdown tìm kiếm lớn

Select box danh sách tỉnh/thành, quốc gia kết hợp ô tìm kiếm — Virtualization đảm bảo ô input không bị lag dù danh sách có hàng nghìn option.

5. Những Lưu Ý Quan Trọng

  • Chiều cao cố định nếu có thể: FixedSizeList đơn giản và nhanh hơn nhiều so với VariableSizeList. Thiết kế UI với chiều cao hàng đồng nhất khi được.

  • Cache chiều cao với VariableSizeList: Đừng đo DOM mỗi lần scroll — cache kết quả đã đo để tránh layout thrashing.

  • Accessibility (A11y): Đảm bảo screen reader vẫn điều hướng được qua danh sách — test với VoiceOver và NVDA.

  • Kết hợp useMemo: Bọc data được truyền vào List trong useMemo để tránh tạo lại mảng và trigger re-render toàn bộ.

Tổng Kết

Virtualization là ranh giới giữa ứng dụng web nghiệp dư và sản phẩm chuyên nghiệp. Nguyên lý đơn giản — chỉ render những gì người dùng nhìn thấy — nhưng tác động lên hiệu năng là phi thường:

  • DOM node: từ hàng chục nghìn xuống còn ~15.

  • Thời gian render: từ vài giây xuống vài millisecond.

  • Memory footprint: giảm đáng kể, Garbage Collector ít căng thẳng hơn.

Bất kỳ ứng dụng nào hiển thị danh sách dài hơn 100 phần tử đều nên cân nhắc áp dụng Virtualization.

Câu hỏi thường gặp

Chia sẻ bài viết
Zalo

Bạn thấy bài viết hữu ích?

Liên hệ với chúng tôi để được tư vấn miễn phí về dịch vụ

Liên hệ ngay

Bài viết liên quan

Ảnh bìa bài viết: Zustand Async: 5 Cách Xử Lý Bất Đồng Bộ Hiệu Quả Trong React
Frontend

Zustand Async: 5 Cách Xử Lý Bất Đồng Bộ Hiệu Quả Trong React

Mọi ứng dụng React thực tế đều phải giao tiếp với API bất đồng bộ. Nếu quản lý kém, ứng dụng dễ rơi vào các vấn đề như UI bị đơ, race condition, rò rỉ bộ nhớ, hay hiển thị dữ liệu cũ. Zustand giải quyết bài toán này với một cú pháp cực kỳ đơn giản — định nghĩa async actions trực tiếp trong store, không cần middleware phức tạp như Redux Thunk hay Saga.

9/5/2026
Ảnh bìa bài viết: Promise Nâng Cao: all, allSettled, race, any — Khi Nào Dùng Cái Nào?
Frontend

Promise Nâng Cao: all, allSettled, race, any — Khi Nào Dùng Cái Nào?

Nếu bạn chỉ dùng async/await tuần tự, ứng dụng của bạn đang bỏ phí tiềm năng hiệu suất — mỗi request phải chờ request trước xong mới bắt đầu. Các phương thức tĩnh của Promise (all, allSettled, race, any) cho phép bạn điều phối nhiều tác vụ bất đồng bộ song song theo chiến lược phù hợp từng bài toán.

9/5/2026
Ảnh bìa bài viết: Zustand Async: 5 Cách Xử Lý Bất Đồng Bộ Hiệu Quả Trong React
Frontend

Zustand Async: 5 Cách Xử Lý Bất Đồng Bộ Hiệu Quả Trong React

Mọi ứng dụng React thực tế đều phải giao tiếp với API bất đồng bộ. Nếu quản lý kém, ứng dụng dễ rơi vào các vấn đề như UI bị đơ, race condition, rò rỉ bộ nhớ, hay hiển thị dữ liệu cũ. Zustand giải quyết bài toán này với một cú pháp cực kỳ đơn giản — định nghĩa async actions trực tiếp trong store, không cần middleware phức tạp như Redux Thunk hay Saga.

1/4/2026