Виртуализация списков в React быстрый рендер без лагов
Виртуализация списков в React позволяет рендерить только видимые элементы, существенно снижая нагрузку на браузер и улучшая отзывчивость UI.
Виртуализация списков в React решает проблему рендеринга большого количества DOM-элементов. При скролле в обычном списке браузер хранит в DOM все строки, что приводит к высоким затратам памяти и частым пересчетам. Виртуализованный список оставляет в DOM лишь те элементы, которые находятся в видимой области (viewport) и небольшую буферную зону.
1. Что такое виртуализация и почему она работает
Виртуализация это техника, при которой в DOM присутствуют только видимые элементы. Все, что находится за пределами viewport, считается “виртуальным” и не существует в реальном DOM. Библиотеки измеряют высоту элементов и позиционируют их с помощью translateY, что сохраняет обычный скролл без избыточных узлов.
| Сценарий | Кол-во DOM-элементов |
|---|---|
| Полный список | 20 000 |
| Виртуализированный | 10-20 + буфер |
2. Выбор инструмента: react-window vs react-virtualized
| Параметр | react-window | react-virtualized |
|---|---|---|
| Размер пакета | ~2 KB (gzip) | ~30 KB |
| API | минималистичный | более объемный |
| Поддержка гридов | FixedSizeGrid | MultiGrid |
| Документация | лаконичная | подробная |
Для большинства задач рекомендуется 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. Тестирование производительности
- В Chrome DevTools откройте Performance, запишите скролл и проверьте количество
LayoutиPaint-событий их должно быть существенно меньше, чем при полном рендере. - В React DevTools наблюдайте, что ререндерятся только видимые компоненты
Row. - При необходимости задайте буфер
overscanCount:
<List overscanCount={5} /* … */ >
FAQ / чеклист
- Не используйте
indexв качествеkeyэто приводит к лишним ререндеру при изменении списка. Подробнее о правильном рендеринге смотрите Рендеринг и реконсиляция в React. - Выбирайте адекватный
overscanCountслишком маленькое значение может вызвать “мигание” при быстром скролле. - Для переменной высоты строк используйте
react-virtuoso. - Не храните весь массив в локальном состоянии списка подключайте селектор или пагинацию.
- Проверяйте совместимость
position: stickyнекоторые библиотеки требуют дополнительных настроек. - Помните, что правильная настройка виртуализации списков в React избавит от лишних рендеров и повысит отзывчивость интерфейса.Дополнительно используйте мемоизацию компонентов для максимальной производительности.
Виртуализация практический способ обеспечить плавный скролл в больших таблицах, чат-лентах и бесконечных списках. Именно Виртуализация списков в React позволяет достичь такой производительности без ущерба стабильности проекта.