[Lv3] Virtual Scrolling: эффективный рендеринг больших списков
Virtual scrolling поддерживает небольшой размер DOM, рендеря только видимое окно плюс буфер.
Ситуация
Большие таблицы с частыми обновлениями могут создавать десятки тысяч DOM-узлов, что приводит к:
- Медленному начальному рендерингу
- Подёргиваниям при прокрутке
- Высокому потреблению памяти
- Дорогостоящим обновлениям при событиях в реальном времени
Основная идея
Вместо рендеринга всех строк рендерить только:
- Видимые строки
- Небольшой overscan до и после видимой области
При изменении позиции прокрутки контейнеры строк переиспользуются и обновляется отображаемое окно данных.
Базовая реализация (фиксированная высота строк)
const rowHeight = 48;
const viewportHeight = 480;
const visibleCount = Math.ceil(viewportHeight / rowHeight);
const startIndex = Math.floor(scrollTop / rowHeight);
const endIndex = startIndex + visibleCount + 6; // overscan
<div style={{ height: totalRows * rowHeight }}>
<div style={{ transform: `translateY(${startIndex * rowHeight}px)` }}>
{rows.slice(startIndex, endIndex).map(renderRow)}
</div>
</div>
Особенности переменной высоты строк
Для динамического содержимого:
- Измерять высоту строк лениво
- Вести префиксные суммы смещений
- Использовать бинарный поиск для сопоставления
scrollTopс индексом
Если высота строк сильно варьируется, обычно безопаснее использовать библиотеку.
Проблемы взаимодействия и их решения
- Сохранять стабильные ключи для предотвращения ненужных перемонтирований
- Мемоизировать компоненты строк
- Debounce для тяжёлых побочных эффектов от событий прокрутки
- Сохранять якорь прокрутки при обновлении списка
Когда стоит избегать virtual scroll
- Маленькие наборы данных (сложность может не оправдаться)
- Сценарии, требующие всех DOM-узлов для нативных операций браузера
- Сильно нерегулярные макеты, которые сложно измерить
Краткое резюме для собеседования
Я применяю virtual scrolling, когда количество ст рок велико и стоимость рендеринга преобладает. Ключевое — оконный рендеринг с overscan, стабильные ключи и продуманная стратегия обновления, чтобы прокрутка оставалась плавной при частых изменениях данных.