Giới thiệu
Khi xây dựng ứng dụng Front‑End bằng ReactJS, việc hiển thị một danh sách có hàng nghìn mục thường gây ra hiện tượng giật lag do số lượng phần tử DOM tăng lên đáng kể. Trong bài viết này, chúng ta sẽ tìm hiểu cách giảm tải render bằng hai kỹ thuật chính: virtualization (sử dụng thư viện react-window) và memoization (sử dụng React.memo và useMemo).
Virtualized List là gì?
Virtualization là phương pháp chỉ render những phần tử hiện đang hiển thị trên màn hình, các phần tử còn lại được giữ trong bộ nhớ ảo. Khi người dùng cuộn, các phần tử mới sẽ được tạo ra và các phần tử cũ được tái sử dụng, giảm đáng kể số lượng node trong DOM. Thư viện phổ biến nhất cho React hiện nay là react-window (phiên bản nhẹ hơn react-virtualized).
Cài đặt
npm install react-window
Kết hợp Virtualized và memoization
Virtualization giúp giảm số lượng phần tử thực tế, nhưng nếu mỗi mục trong danh sách vẫn thực hiện các phép tính nặng mỗi khi render, hiệu năng vẫn sẽ bị ảnh hưởng. Vì vậy, chúng ta cần memoize các component con để tránh render lại không cần thiết.
Sử dụng React.memo cho hàng danh sách
Component Row sẽ nhận index, style và data từ react-window. Bằng cách bọc Row bằng React.memo, React sẽ so sánh props shallow và chỉ render lại khi data[index] thực sự thay đổi.
Memoize dữ liệu danh sách với useMemo
Khi danh sách được lọc hoặc sắp xếp, chúng ta nên tính toán kết quả một lần và lưu trong useMemo. Điều này ngăn việc tính toán lại mỗi khi component cha re‑render.
Ví dụ thực tế
Dưới đây là một component hoàn chỉnh sử dụng react-window kết hợp React.memo và useMemo để hiển thị danh sách 10.000 mục.
import React, { memo, useMemo } from 'react';
import { FixedSizeList as List } from 'react-window';
// Component hàng danh sách, được memo để tránh render lại không cần thiết
const Row = memo(({ index, style, data }) => (
<div style={style}>
{data[index].title}
</div>
));
function VirtualizedList({ items, filter }) {
// Memoize danh sách đã lọc để không tính lại khi filter không thay đổi
const filteredItems = useMemo(() => {
return items.filter(item => item.title.toLowerCase().includes(filter.toLowerCase()));
}, [items, filter]);
return (
<List
height={600}
itemCount={filteredItems.length}
itemSize={35}
width="100%"
itemData={filteredItems}
>
{Row}
</List>
);
}
export default VirtualizedList;Trong đoạn code trên:
Rowđược bọc bằngmemođể React chỉ cập nhật khidata[index]thay đổi.filteredItemsđược tạo bằnguseMemo, phụ thuộc vàoitemsvàfilter.- Thuộc tính
heightvàitemSizexác định kích thước viewport và chiều cao mỗi hàng, giúpreact-windowtính toán vị trí một cách nhanh chóng.
Kiểm tra hiệu năng
Để đo lường cải thiện, bạn có thể sử dụng console.time và console.timeEnd quanh quá trình render, hoặc công cụ React Profiler trong Chrome DevTools. Thông thường, việc chuyển từ render toàn bộ 10.000 mục sang virtualized list giảm thời gian render từ vài giây xuống dưới 100ms.
Kết luận
Virtualization và memoization là hai công cụ mạnh mẽ giúp tối ưu hiệu năng khi làm việc với danh sách lớn trong React. Khi áp dụng đúng, bạn sẽ giảm đáng kể số lượng node trong DOM và tránh các render không cần thiết, mang lại trải nghiệm mượt mà cho người dùng.
Nếu muốn học sâu hơn về cách xây dựng ứng dụng React chuyên nghiệp, Tham khảo khóa học "Lập trình Front-End với ReactJS + TypeScript" tại đây.







