Введение
Иногда появляются задачи на вывод большого кол-ва элементов, без возможности подгрузки порциями с помощью пагинации или прокрутки страницы пользователем.
В таком случае без оптимизированного решения приложение будет тормозить, что естественно не соотвествует логике использования React. Для таких сценариев подойдут виртуализация и библиотека react-window
.
Зачем использовать react-window?
react-window
позволяет рендерить только видимые элементы списка, что минимизирует потребление памяти и увеличивает производительность. Вместо отображения всех элементов, библиотека создает небольшое количество DOM-узлов, которые обновляются по мере прокрутки.
Установка
Для начала установим необходимые зависимости:
npm install react-window
Если проект использует TypeScript, убедитесь, что установлены типы для библиотеки:
npm install --save-dev @types/react-window
Реализация бесконечной ленты
Компонент List с использованием react-window
Создадим компонент для отображения списка:
import React from 'react';
import { FixedSizeList as List } from 'react-window';
type ItemProps = {
index: number;
style: React.CSSProperties;
};
const items = Array.from({ length: 1000 }, (_, index) => `Элемент ${index + 1}`);
const Row: React.FC<ItemProps> = ({ index, style }) => (
<div style={style}>
{items[index]}
</div>
);
const VirtualizedList: React.FC = () => {
return (
<List
height={500} // Высота видимой области
itemCount={items.length} // Количество элементов
itemSize={35} // Высота одного элемента
width={300} // Ширина списка
>
{Row}
</List>
);
};
export default VirtualizedList;
Объяснение кода
- Компонент Row: Отвечает за отрисовку одного элемента списка.
- Свойства List:
height
— задает высоту видимой области.itemCount
— количество элементов в списке.itemSize
— фиксированная высота одного элемента.width
— ширина контейнера.
Бесконечная загрузка данных
Для реализации подгрузки элементов по мере прокрутки потребуется добавить обработчик события скроллинга.
import React, { useState, useCallback } from 'react';
import { FixedSizeList as List } from 'react-window';
type ItemProps = {
index: number;
style: React.CSSProperties;
};
const generateItems = (start: number, count: number) =>
Array.from({ length: count }, (_, index) => `Элемент ${start + index + 1}`);
const InfiniteScrollList: React.FC = () => {
const [items, setItems] = useState(() => generateItems(0, 100));
const loadMoreItems = useCallback(() => {
setItems((prevItems) => [...prevItems, ...generateItems(prevItems.length, 50)]);
}, []);
const isItemLoaded = (index: number) => index < items.length;
const Row: React.FC<ItemProps> = ({ index, style }) => {
if (!isItemLoaded(index)) {
return <div style={style}>Загрузка...</div>;
}
return <div style={style}>{items[index]}</div>;
};
return (
<List
height={500}
itemCount={items.length + 1} // +1 для индикатора загрузки
itemSize={35}
width={300}
onItemsRendered={({ visibleStopIndex }) => {
if (visibleStopIndex === items.length - 1) {
loadMoreItems();
}
}}
>
{Row}
</List>
);
};
export default InfiniteScrollList;
Ключевые моменты реализации
generateItems
: Функция для создания новых элементов.loadMoreItems
: Подгружает дополнительные элементы при достижении конца списка.onItemsRendered
: Отслеживает видимые элементы и инициирует загрузку при необходимости.
Заключение
Использование react-window
в связке с React и TypeScript позволяет легко реализовать производительное приложение с бесконечной лентой. Виртуализация сокращает использование ресурсов, а подгрузка данных обеспечивает масштабируемость.