Виртуализация списков в 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 позволяет достичь такой производительности без ущерба стабильности проекта.