Виртуализация

Виртуализация — это техника оптимизации рендеринга больших списков элементов в пользовательском интерфейсе. В обычных условиях React рендерит все элементы списка в DOM, что при сотнях или тысячах элементов приводит к значительным проблемам с производительностью. React Aria предоставляет высокоуровневые хуки и утилиты для безопасной и эффективной виртуализации, сохраняя доступность интерфейсов.

Хук useVirtualizer

Ключевым инструментом для виртуализации в React Aria является хук useVirtualizer. Он обеспечивает отслеживание видимых элементов, вычисление размеров контейнера и элементов, а также управление прокруткой.

import { useVirtualizer } from '@react-aria/virtualizer';

Основные параметры хука:

  • count — общее количество элементов в списке.
  • getScrollElement — функция, возвращающая контейнер, на котором осуществляется прокрутка.
  • estimateSize — функция, возвращающая предполагаемую высоту или ширину элемента.
  • overscan — количество элементов до и после видимой области, которые будут рендериться для плавного скроллинга.

Пример базового использования:

function VirtualList({ items }) {
  const scrollRef = useRef(null);

  const virtualizer = useVirtualizer({
    count: items.length,
    getScrollElement: () => scrollRef.current,
    estimateSize: () => 50,
    overscan: 5
  });

  return (
    <div ref={scrollRef} style={{ height: 400, overflow: 'auto' }}>
      <div style={{ height: virtualizer.getTotalSize(), position: 'relative' }}>
        {virtualizer.getVirtualItems().map(virtualRow => (
          <div
            key={virtualRow.index}
            style={{
              position: 'absolute',
              top: virtualRow.start,
              height: virtualRow.size,
              width: '100%'
            }}
          >
            {items[virtualRow.index]}
          </div>
        ))}
      </div>
    </div>
  );
}

Управление размерами элементов

React Aria поддерживает как фиксированные, так и динамические размеры элементов. Для динамических размеров используется функция measureElement, которая позволяет виртуализатору точно отслеживать размер каждого элемента после рендера.

const measureElement = (el) => el.getBoundingClientRect().height;

При изменении размеров элементов хук автоматически обновляет позиции и смещения всех виртуализированных элементов.

Виртуализация горизонтальных списков

Помимо вертикальных списков, React Aria поддерживает горизонтальные прокрутки. Для этого достаточно передать параметр ориентации:

const virtualizer = useVirtualizer({
  count: items.length,
  getScrollElement: () => scrollRef.current,
  estimateSize: () => 120,
  orientation: 'horizontal',
  overscan: 3
});

Стилизация контейнера изменяется соответствующим образом: вместо высоты фиксируется ширина и прокрутка осуществляется по оси X.

Интеграция с компонентами React Aria

Виртуализация тесно интегрируется с другими компонентами React Aria, например ListBox, Menu, Table. Это позволяет поддерживать полную доступность элементов:

  • Клавиатурная навигация автоматически работает только с видимыми элементами.
  • ARIA-атрибуты корректно применяются к виртуализированным элементам.
  • Фокус переносится на элементы при прокрутке без потери контекста.

Пример интеграции с ListBox:

import { useListBox, useListBoxSection } from '@react-aria/listbox';

function VirtualizedListBox({ items, listBoxProps }) {
  const scrollRef = useRef(null);
  const virtualizer = useVirtualizer({
    count: items.length,
    getScrollElement: () => scrollRef.current,
    estimateSize: () => 40,
    overscan: 5
  });

  return (
    <div ref={scrollRef} style={{ height: 300, overflow: 'auto' }}>
      <div style={{ height: virtualizer.getTotalSize(), position: 'relative' }}>
        {virtualizer.getVirtualItems().map(virtualRow => (
          <div
            key={virtualRow.index}
            style={{
              position: 'absolute',
              top: virtualRow.start,
              height: virtualRow.size,
              width: '100%'
            }}
          >
            {items[virtualRow.index].name}
          </div>
        ))}
      </div>
    </div>
  );
}

Тонкости производительности

  • Overscan стоит настраивать с учетом скорости прокрутки и размера элементов. Слишком большое значение увеличивает нагрузку на рендер, слишком маленькое — делает прокрутку рывками.
  • Memoization элементов списка помогает избежать лишних пересчетов и повторных рендеров.
  • Оптимизация размеров особенно важна при динамических элементах с контентом разной высоты.

Поддержка бесконечной прокрутки

React Aria можно сочетать с подгрузкой данных по мере скроллинга. Для этого используется событие onScroll на контейнере и проверка индекса последнего виртуализированного элемента:

const lastItem = virtualizer.getVirtualItems().slice(-1)[0];
if (lastItem.index >= items.length - 1) {
  loadMoreItems();
}

Это позволяет создавать списки с тысячами элементов без значительного влияния на производительность.

Итоговое преимущество

Виртуализация в React Aria позволяет:

  • Рендерить только видимые элементы и небольшие запасы, снижая нагрузку на DOM.
  • Поддерживать доступность интерфейса без дополнительной логики.
  • Работать с динамическими и горизонтальными списками.
  • Интегрироваться с другими компонентами библиотеки без потери функциональности.

Эффективная виртуализация становится фундаментом для создания масштабируемых и отзывчивых интерфейсов, особенно при работе с большими объемами данных.