Efficiently Rendering Large Lists (Virtual Lists)
- 文章發表於
Have you ever encountered scenarios in your projects where you need to render large lists, such as big data tables or simply displaying multiple items in a list format? I remember facing a similar issue in my first job—I naively used map to render a list with over ten thousand items, only to find the page becoming extremely sluggish and even crashing. The main reason is that rendering thousands of items all at once into the DOM forces the browser to spend a significant amount of time rendering these elements. During interactions, this also leads to severe performance issues due to repaint/reflow.
This article will explain the principles behind virtual lists and how to implement them.
What is a Virtual List?
Whether you're viewing data on a computer or a mobile device, there's a maximum visible height, so there's no need to render all the data into the DOM at once. Virtual lists address this exact problem. The core idea is to render only the data currently in the viewport, meaning only a small number of elements are rendered at any given time. Simultaneously, we simulate the total height of the entire list to achieve an effect similar to infinite scrolling. As the user scrolls through the list, new items entering the visible range are loaded in real-time, while old items leaving the visible range are removed.
Through the interactive demo above, you can better understand the underlying principles. By setting the number of items and the height of each item, you can simulate the relationship between the viewport and the entire list by adjusting the Scroll Position. For example, if the viewport only has space for 10 items, even if there are 100 items in total, only 10 items need to be rendered. The remaining 90 items are simulated, achieving an effect similar to infinite scrolling.
<div style="height: 500px; overflow: auto;"><div style="height: 500000px;"></div></div>
Implementing a Virtual List
From the interactive UI above, you can see that the most important aspect of implementing a virtual list is determining the start and end of the visible area, represented by startIndex and endIndex. These values are calculated as follows:
const startIndex = Math.floor(scrollTop / itemHeight);const visibleItemCount = Math.ceil(containerHeight / itemHeight);const endIndex = startIndex + visibleItemCount;
Next, we need to calculate the actual position of each item to know where it should be placed in the list:
const itemPosition = itemIndex * itemHeight;
After calculating the start and end of the visible area and the position of each item, we then compute the total height of all the data:
const totalHeight = itemCount * itemHeight;
One final optimization technique is using overscan to improve list rendering. This involves rendering items just outside the visible area to prevent visual jumps when scrolling.
const overscanCount = 3;const startWithOverscan = Math.max(0, startIndex - overscanCount);const endWithOverscan = Math.min(itemCount - 1, endIndex + overscanCount);
Finally, we just need to add an onScroll event to the parent container and update the scrollTop value within it to implement a basic virtual list.
Conclusion
While the implementation above isn't suitable for production environments, it helps you understand the principles behind virtual lists. For production use, I recommend libraries like react-window or tanstack-virtual.
