Вопрос или проблема
Прямо сейчас у меня есть “коробка” с заданной высотой, в которой содержатся эти юникодные глифы (более 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
в сочетании с динамическим определением высоты контейнера. Далее приведен пример, как это можно сделать.
Шаги для реализации
-
Определите контейнер для списка: Вы можете использовать
ref
для отслеживания высоты контейнера, который будет динамически изменяться в зависимости от содержимого. -
Используйте
react-window
и высоту контейнера: Как только высота контейнера будет известна, вы можете передать это значение в компонентList
. -
Настройте обработчики для изменения высоты: Вы можете добавить обработчики для изменения размеров окна, чтобы высота контейнера обновлялась при изменении размеров окна браузера.
Пример кода
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
. Таким образом, вы можете избавиться от необходимости указывать фиксированную высоту для контейнера, при этом гарантируя, что только элементы, находящиеся в области видимости, будут рендериться, что позволяет эффективно обрабатывать большое количество строк.