Бесконечная прокрутка на React

Енов в телефоне листает сообщения

Введение

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

В таком случае без оптимизированного решения приложение будет тормозить, что естественно не соотвествует логике использования 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;

Объяснение кода

  1. Компонент Row: Отвечает за отрисовку одного элемента списка.
  2. Свойства 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;

Ключевые моменты реализации

  1. generateItems: Функция для создания новых элементов.
  2. loadMoreItems: Подгружает дополнительные элементы при достижении конца списка.
  3. onItemsRendered: Отслеживает видимые элементы и инициирует загрузку при необходимости.

Заключение

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

Tasty Coffee

Консультация

Оставьте заявку на консультацию

Отправляя заявку, вы соглашаетесь с политикой конфиденциальности

О проекте

Расскажите о проекте, чтобы я мог подготовить предварительное предложение

Отправляя заявку, вы соглашаетесь с политикой конфиденциальности