带有 ReactJS 的虚拟化列表



最近我遇到了reat-window库,它很棒而且很方便。这让我思考它是如何构建的,所以我决定尝试一下并构建我自己的虚拟化列表

但是,列表只能滚动到项目"60"。想知道我的索引计算有什么问题,并查看 react-window 中的代码,似乎我们正在做类似的事情 src1 src2。

知道我的指数计算有什么问题吗

import React, { useMemo, useCallback, useState } from 'react';
const ListItem = ({ val, height }) => {
return <li style={{ height: `${height}px` }}>{val}</li>;
};
const ITEM_HEIGHT = 20;
const CONTAINER_HEIGHT = 300;
const BUFFER = Math.ceil(CONTAINER_HEIGHT / ITEM_HEIGHT);
export const App = () => {
const [scrollTop, setScrollTop] = useState(0);
const allItems = useMemo(() => {
const items = [];
for (let i = 0; i < 500; i++) {
items.push(<ListItem val={i} height={ITEM_HEIGHT} />)
}
return items;
}, [ITEM_HEIGHT]);
const onScrollHandler = useCallback((event) => {
setScrollTop(event.currentTarget.scrollTop);
}, [allItems, setScrollTop]);
// start index = (total scrolled pixel / row height) - buffer
const start = Math.max(0, Math.floor(scrollTop / ITEM_HEIGHT) - BUFFER);
// end index   = (total scrolled pixel + list height) / row height + buffer
const end = Math.min(allItems.length - 1, Math.ceil((scrollTop + CONTAINER_HEIGHT) / ITEM_HEIGHT) + BUFFER);
const itemsToBeRender = allItems.slice(start, end);
return (
<div
style={{ overflowY: "scroll" }}
onScroll={onScrollHandler}>
<ul
style={{ height: `${CONTAINER_HEIGHT}px` }}
>
{itemsToBeRender}
</ul>
</div>
);
};

我做了一些谷歌搜索并遇到了这篇文章。添加"位置"属性后,一切都按预期工作。

import React, { useMemo, useCallback, useState } from 'react';
const ITEM_HEIGHT = 20;
const CONTAINER_HEIGHT = 300;
const BUFFER = Math.ceil(CONTAINER_HEIGHT / ITEM_HEIGHT);
export const App = () => {
const [scrollTop, setScrollTop] = useState(0);
const allItems = useMemo(() => {
const items = [];
for (let i = 0; i < 200; i++) {
const style = {
height: `${ITEM_HEIGHT}px`,
position: "absolute",
top: `${i * ITEM_HEIGHT}px`,
};
items.push(<li key={i} style={style} >{i}</li>)
}
return items;
}, [ITEM_HEIGHT]);
const onScrollHandler = useCallback((event) => {
setScrollTop(event.currentTarget.scrollTop);
}, [allItems, setScrollTop]);
// fake we have a lots of item, so that the scroll bar will always show up
const fullHeight = allItems.length * ITEM_HEIGHT;
const start = Math.max(0, Math.floor(scrollTop / ITEM_HEIGHT) - BUFFER);
const end = Math.min(
allItems.length - 1,
Math.floor((scrollTop + CONTAINER_HEIGHT) / ITEM_HEIGHT) + BUFFER);
const itemsToBeRender = allItems.slice(start, end + 1);
return (
<div
style={{ overflowY: "scroll", height: `${CONTAINER_HEIGHT}px` }}
onScroll={onScrollHandler}>
<ul
style={{ height: `${fullHeight}px`, position: "relative" }}
>
{itemsToBeRender}
</ul>
</div>
);
};

最新更新