Как установить высоту списка react-window равной высоте фактического списка, оставаясь при этом виртуализированным?

Вопрос или проблема

Прямо сейчас у меня есть “коробка” с заданной высотой, в которой содержатся эти юникодные глифы (более 200 тысяч строк), и я использую react-window для виртуальной прокрутки (вертикально):

введите описание изображения здесь

Как мне устранить необходимость в коробке с явным размером и сделать так, чтобы белая область контента была высотой виртуализированного списка, при этом список по-прежнему оставался виртуализированным? Таким образом, страница будет прокручиваться так, как вы обычно ожидаете, только с этим гигантским списком видимыми будут только элементы в области просмотра браузера? Это возможно с помощью react-window?

По сути, я просто делаю это:

import { VariableSizeList as List } from 'react-window'

<div className="w-full">
  <List
    className="w-full"
    height={containerHeight}
    itemCount={rows.length}
    itemSize={getItemSize}
    width={containerWidth}
  >
    {({ index, style }) => (
      <ListItem
        style={style}
        index={index}
      />
    )}
  </List>
</div>

Ответ или решение

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

Шаги для реализации

  1. Определите контейнер для списка: Вы можете использовать ref для отслеживания высоты контейнера, который будет динамически изменяться в зависимости от содержимого.

  2. Используйте react-window и высоту контейнера: Как только высота контейнера будет известна, вы можете передать это значение в компонент List.

  3. Настройте обработчики для изменения высоты: Вы можете добавить обработчики для изменения размеров окна, чтобы высота контейнера обновлялась при изменении размеров окна браузера.

Пример кода

import React, { useEffect, useRef, useState } from 'react';
import { VariableSizeList as List } from 'react-window';

const DynamicHeightList = ({ rows, getItemSize }) => {
  const containerRef = useRef(null);
  const [containerHeight, setContainerHeight] = useState(0);

  useEffect(() => {
    const updateHeight = () => {
      if (containerRef.current) {
        setContainerHeight(containerRef.current.getBoundingClientRect().height);
      }
    };

    // Установим высоту при монтировании
    updateHeight();

    // Обновление высоты при изменении размеров окна
    window.addEventListener('resize', updateHeight);
    return () => {
      window.removeEventListener('resize', updateHeight);
    };
  }, [rows]); // Обновим высоту, если изменится массив rows

  return (
    <div ref={containerRef} className="w-full">
      <List
        className="w-full"
        height={containerHeight}
        itemCount={rows.length}
        itemSize={getItemSize}
        width={'100%'}
      >
        {({ index, style }) => (
          <ListItem style={style} index={index} />
        )}
      </List>
    </div>
  );
};

export default DynamicHeightList;

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

  • Мы создаем реф containerRef, который указывает на контейнер с классом w-full.
  • При помощи useEffect мы добавляем обработчик, который обновляет высоту при изменении размеров окна и при монтировании компонента.
  • Мы используем метод getBoundingClientRect() для получения реальной высоты контейнера.
  • В компоненте List высота передается из состояния containerHeight, что позволяет ему адаптироваться к изменению высоты контейнера.

Заключение

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

Оцените материал
Добавить комментарий

Капча загружается...