Перейти к основному содержимому

[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, стабильные ключи и продуманная стратегия обновления, чтобы прокрутка оставалась плавной при частых изменениях данных.