Назад
Назад к заметкам
· 4 мин чтения

Виртуализация списков в React быстрый рендер без лагов

Виртуализация списков в React позволяет рендерить только видимые элементы, существенно снижая нагрузку на браузер и улучшая отзывчивость UI.

reactperformancevirtualizationlists

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


1. Что такое виртуализация и почему она работает

Виртуализация это техника, при которой в DOM присутствуют только видимые элементы. Все, что находится за пределами viewport, считается “виртуальным” и не существует в реальном DOM. Библиотеки измеряют высоту элементов и позиционируют их с помощью translateY, что сохраняет обычный скролл без избыточных узлов.

СценарийКол-во DOM-элементов
Полный список20 000
Виртуализированный10-20 + буфер

2. Выбор инструмента: react-window vs react-virtualized

Параметрreact-windowreact-virtualized
Размер пакета~2 KB (gzip)~30 KB
APIминималистичныйболее объемный
Поддержка гридовFixedSizeGridMultiGrid
Документациялаконичнаяподробная

Для большинства задач рекомендуется react-window: он легкий, прост в настройке и покрывает обычные списки и гриды. react-virtualized имеет смысл, когда нужны специфические функции (sticky-header, фиксированные колонки, динамический размер ячеек).


3. Быстрый старт с react-window

import React from "react";
import { FixedSizeList as List } from "react-window";

const Row = ({
  index,
  style,
}: {
  index: number;
  style: React.CSSProperties;
}) => (
  <div style={style} className="row">
    {`Элемент №${index + 1}`}
  </div>
);

export const VirtualizedList = () => (
  <List
    height={600} // высота видимой области
    itemCount={20000} // общее количество элементов
    itemSize={35} // фиксированная высота строки
    width="100%"
  >
    {Row}
  </List>
);

Главное передавать полученный style в каждый элемент. Все, что выходит за пределы height, не попадает в DOM.


4. Работа с переменной высотой строк

react-window поддерживает только фиксированную высоту. Для переменных размеров лучше использовать react-virtuoso или react-virtualized с CellMeasurer.

import { Virtuoso } from "react-virtuoso";

export const VariableHeightList = () => (
  <Virtuoso
    style={{ height: 600 }}
    totalCount={20000}
    itemContent={(index) => (
      <div className="row">
        {index % 10 === 0 ? <LongText /> : <ShortText />}
      </div>
    )}
  />
);

Автоматическое измерение высоты устраняет визуальные “скачки” при изменении контента.


5. Интеграция с Redux / React Query

Передача в список полного массива из глобального состояния приводит к лишним ререндеру. Лучше отбирать только текущий диапазон данных.

// selector.js
export const selectVisibleItems = (state, start, end) =>
  state.items.slice(start, end);
import { FixedSizeList as List } from "react-window";
import { useSelector } from "react-redux";
import React from "react";

export const VirtualizedList = () => {
  const [offset, setOffset] = React.useState(0);
  const visible = useSelector((state) =>
    selectVisibleItems(state, offset, offset + 20)
  );

  return (
    <List
      height={600}
      itemCount={visible.length}
      itemSize={35}
      width="100%"
      onItemsRendered={({ visibleStartIndex }) => setOffset(visibleStartIndex)}
    >
      {({ index, style }) => <div style={style}>{visible[index].title}</div>}
    </List>
  );
};

Так мы экономим память и избегаем повторного рендера неотображаемых элементов.


6. Тестирование производительности

  1. В Chrome DevTools откройте Performance, запишите скролл и проверьте количество Layout и Paint-событий их должно быть существенно меньше, чем при полном рендере.
  2. В React DevTools наблюдайте, что ререндерятся только видимые компоненты Row.
  3. При необходимости задайте буфер overscanCount:
<List overscanCount={5} /* … */ >

FAQ / чеклист

  • Не используйте index в качестве key это приводит к лишним ререндеру при изменении списка. Подробнее о правильном рендеринге смотрите Рендеринг и реконсиляция в React.
  • Выбирайте адекватный overscanCount слишком маленькое значение может вызвать “мигание” при быстром скролле.
  • Для переменной высоты строк используйте react-virtuoso.
  • Не храните весь массив в локальном состоянии списка подключайте селектор или пагинацию.
  • Проверяйте совместимость position: sticky некоторые библиотеки требуют дополнительных настроек.
  • Помните, что правильная настройка виртуализации списков в React избавит от лишних рендеров и повысит отзывчивость интерфейса.Дополнительно используйте мемоизацию компонентов для максимальной производительности.

Виртуализация практический способ обеспечить плавный скролл в больших таблицах, чат-лентах и бесконечных списках. Именно Виртуализация списков в React позволяет достичь такой производительности без ущерба стабильности проекта.

Готов начать?

Выбери удобный способ связи — напиши напрямую или оставь заявку

Написать в Telegram

Отвечу в течение пары часов