Почему оптимизация списков так важна?
Современные приложения часто работают с большими объёмами данных. Например, бесконечная лента в соцсетях, списки пользователей или результаты поисковых систем. Если отрендерить все элементы списка сразу, то браузер, скорее всего, падёт под тяжестью DOM-узлов, а пользователь заварит себе третью чашку кофе, пока страница грузится.
Задача проста: рендерить только ту часть списка, которую пользователь видит на экране. Здесь на помощь и приходит библиотека React.Virtualized. Она позволяет создавать виртуализированные списки, рендеря только видимые элементы, а остальные "держит в кэше" до тех пор, пока они не потребуются.
Давайте представим: ваш список содержит 10 000 элементов. Даже если каждый элемент небольшой и весит 1 кБ, браузеру потребуется создать и держать в памяти 10 000 DOM-узлов. Вот несколько проблем, с которыми вы столкнётесь:
- Падение производительности. Браузер будет с трудом обновлять интерфейс, особенно если список динамически изменяется.
- Долгая загрузка страницы. Пользователь увидит белый экран, пока весь список создаётся.
- Проблемы с памятью. Браузер может просто зависнуть из-за недостатка ресурсов.
Всё это приводит к плохому пользовательскому опыту и низкой скорости работы приложения. С помощью React.Virtualized мы сможем избавиться от этих проблем, рендеря только видимые элементы.
Знакомство с React.Virtualized
Для начала установим библиотеку:
npm install react-virtualized
Это библиотека, специально созданная для работы с большими списками, таблицами и сетками.
Основные компоненты React.Virtualized
List: рендерит виртуализированный список.Grid: позволяет рендерить элементы в виде сетки.AutoSizer: автоматически определяет размеры контейнера.CellMeasurer: помогает измерять размеры ячеек, если их содержимое динамическое.
Сегодня мы сосредоточимся на List — самом популярном компоненте.
Пример использования List
Давайте создадим приложение с длинным списком и оптимизируем его с помощью React.Virtualized. Допустим, у нас есть массив из 10 000 элементов:
Шаг 1: Базовый список без оптимизации
Вот как это может выглядеть:
import React from 'react';
const items = Array.from({ length: 10000 }, (_, idx) => `Item ${idx + 1}`);
const SimpleList: React.FC = () => {
return (
<div>
{items.map((item) => (
<div key={item} style={{ padding: '10px', border: '1px solid #ccc' }}>
{item}
</div>
))}
</div>
);
};
export default SimpleList;
Этот код создаёт список из 10 000 элементов. Но если вы запустите его в браузере, то сразу заметите: всё тормозит! Вот где React.Virtualized вступает в игру.
Шаг 2: Использование List из React.Virtualized
Давайте перепишем этот код, добавив виртуализацию:
import React from 'react';
import { List, ListRowRenderer } from 'react-virtualized';
import 'react-virtualized/styles.css'; // Стили для работы List
const items = Array.from({ length: 10000 }, (_, idx) => `Item ${idx + 1}`);
const VirtualizedList: React.FC = () => {
// Шаг 1: Функция для рендера строки списка
const rowRenderer: ListRowRenderer = ({ index, key, style }) => (
<div key={key} style={style}>
{items[index]}
</div>
);
return (
// Шаг 2: Компонент List
<List
width={800} // Ширина списка
height={600} // Высота списка (окно просмотра)
rowCount={items.length} // Общее количество элементов
rowHeight={50} // Высота одной строки
rowRenderer={rowRenderer} // Функция рендера строки
/>
);
};
export default VirtualizedList;
Объяснение кода
rowRenderer— это функция, которая отвечает за рендеринг одной строки списка. Она принимает параметры:index— индекс элемента в массиве.key— уникальный ключ элемента (важно для производительности).style— стили для строки (например, чтобы позиционировать её правильно).
List— это сам компонент списка:widthиheightзадают размеры окна просмотраviewport.rowCountуказывает общее количество элементов.rowHeightзадаёт фиксированную высоту строки.
Дополнительные возможности React.Virtualized
Окей, мы сделали базовый виртуализированный список. Но что, если:
Высота элементов списка разная?
Для работы с разноразмерными элементами используется компонент
CellMeasurer. Он автоматически измеряет высоту строки и передаёт её вList.Контейнер гибкий, и его размеры меняются?
В этом случае можно использовать
AutoSizer. Этот компонент автоматически определяет ширину и высоту списка.
Пример с AutoSizer:
import React from 'react';
import { List, AutoSizer } from 'react-virtualized';
const items = Array.from({ length: 10000 }, (_, idx) => `Item ${idx + 1}`);
const AutoSizedList: React.FC = () => {
const rowRenderer = ({ index, key, style }: any) => (
<div key={key} style={style}>
{items[index]}
</div>
);
return (
<AutoSizer>
{({ width, height }) => (
<List
width={width} // Ширина определяется автоматически
height={height} // Высота тоже
rowCount={items.length}
rowHeight={50}
rowRenderer={rowRenderer}
/>
)}
</AutoSizer>
);
};
export default AutoSizedList;
Преимущества React.Virtualized
- Экономия памяти. DOM содержит только те элементы, которые видимы.
- Ускорение загрузки. Список рендерится быстрее, так как не требуется создавать весь массив DOM-узлов.
- Гибкость. Можно легко комбинировать с другими компонентами, такими как
Gridдля таблиц илиAutoSizerдля адаптации под экран.
Типичные ошибки и сложности
- Неправильное использование стилей. Не забывайте, что
style, передаваемый вrowRenderer, обязателен! Он определяет позицию элемента. - Сложный рендеринг в
rowRenderer. ЕслиrowRendererделает слишком много вычислений, это негативно повлияет на производительность. - Неподходящие размеры окна. Следите за тем, чтобы
widthиheightуказывали реальныйviewport.
Реальное применение
Вы уже догадались, что оптимизация списков с React.Virtualized пригодится, если вы работаете с:
- Лентами новостей.
- Таблицами с тысячами строк.
- Любыми приложениями с бесконечными списками данных.
Теперь вы готовы добавить виртуализацию в любые свои проекты и заставить большие списки летать, словно они состоят из трёх элементов!
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ