npm package: @salutejs/use-virtual
Description: Виртуализация длинных списков
Author: Salute Frontend Team
Latest version: 2.0.0

# @salutejs/use-virtual

Виртуализация длинного списка элементов. Позволяет рендерить нужное количество элементов,
которое необходимо отобразить во "вьюпорте" или контейнере.
Это позволит значительно улучшить отзывчивость интерфейса за счет сокращения времени рендеринга.

## Installation

```bash
npm install @salutejs/use-virtual --save
```

### Options

```ts
type VirtualProps = {
    /**
     * Контейнер, внутри которого виртуализация.
     * Если есть скролл, то контейнер со скроллом.
     */
    parentRef: React.RefObject<HTMLDivElement | null>;
    /**
     * Ось направления прокрутки списка элементов:
     * 'x' - горизонтальная, 'y' - вертикальная.
     * По умолчанию = 'x'.
     */
    axis?: Axis;
    /**
     * Количество всех элементов в списке.
     */
    itemCount: number;
    /**
     * Вычисление размера элемента в зависимости от индекса.
     * По умолчанию размер = 50px.
     * Функция должна быть замемоизирована или вынесена из рендера.
     */
    estimateSize: (index: number) => number;
    /**
     * Количество элементов за видимой областью.
     * Нужно при быстром скролле, чтобы
     * пользователь не видел пустоту.
     */
    overscan?: number;
    /**
     * Отступ в начале, используется при центрировании крайних элементов, px.
     */
    paddingStart?: number;
    /**
     * Отступ в конце, используется при центрировании крайних элементов, px.
     */
    paddingEnd?: number;
    /**
     * Переопределение функции скролла
     * к нужному элементу при
     * вызове scrollToIndex.
     */
    scrollToFn?: (offset: number) => void;
    /**
     * Получение кастомного ключа
     * для элемента по индекс.
     * TODO: пофиксить, не работает сейчас
     */
    keyExtractor?: (index: number) => number | string;
    /**
     * Центрирование активного элемента при скролле
     */
    scrollAlign?: ScrollAlign;
    /**
     * Количество кадров для throttle
     * при переключении с клавиатуры.
     * По дефолту 12 (~200ms при 60 FPS)
     */
    framesToThrottle?: number;
    /**
     * Сохранять текущее состояние скролла.
     * Актуально если рендер элементов тяжелый
     * и требуется отрендерить превью во избежание
     * зависания интерфейса во время скролла.
     */
    useIsScrolling?: boolean;
    /**
     * Начальный текущий элемент (currentIndex).
     * Если нужно при обновлении компонента изменить сurrentIndex,
     * то следует использовать upIndex / downIndex / upIndexAndRange / downIndexAndRange.
     * Учитывается только при монтировании компонента.
     */
    initialCurrentIndex?: number;
    /**
     * Начальные индексы (initialRange.start - initialRange.end) для отображения элементов (visibleItems),
     * включая initialRange.end
     * Учитывается только при монтировании компонента.
     */
    initialRange?: VisibleRange;
    /**
     * Сколько кадров дебаунсить для
     * вычисления currentIndex после скролла.
     * По умолчанию debouncedFramesScrollSync = 1.
     * Для useVirtualSmoothScroll debouncedFramesScrollSync = 2.
     */
    debouncedFramesScrollSync?: number;
};
```

### Example

```ts
const estimateSize = () => 300;

const VirtualKeyboard = () => {
    const { visibleItems, currentIndex } = useVirtualKeyboard({
        itemCount: fixturesVirtualizedItems.length,
        limit: 5,
        estimateSize,
        axis: 'x',
    });

    return (
        <StyledCarouselWrapperHorizontal>
            {visibleItems.map(({ index }) => {
                const item = fixturesVirtualizedItems[index];

                return (
                    <CarouselItem
                        key={index}
                        focused={currentIndex === index}
                        width={300}
                        height={300}
                        item={item}
                        gap={20}
                    />
                );
            })}
        </StyledCarouselWrapperHorizontal>
    );
};
```