Skip to content

Commit 0d7ea98

Browse files
committed
fix: optimize logic
1 parent bbe6772 commit 0d7ea98

File tree

2 files changed

+48
-52
lines changed

2 files changed

+48
-52
lines changed

src/App.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ function App() {
2626
<VirtualList
2727
items={items}
2828
style={{ height: '600px' }}
29-
itemSize={21}
3029
></VirtualList>
3130
</div>
3231
</div>

src/components/VirtualList.tsx

Lines changed: 48 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -13,69 +13,66 @@ export function VirtualList(
1313
props,
1414
) {
1515
const buffer = props.buffer || 100
16-
let scrollTop = 0
17-
const itemSize = props.itemSize || 100
18-
let listSize = props.listSize || 1000
16+
const [itemSize, setitemSize] = useState(props.itemSize || 100);
1917
const count = props.items.length
2018
const list = useRef(null);
21-
const [visible, setvisible] = useState([]);
22-
const [listInnerStyle, setlistInnerStyle] = useState(() => ({}));
19+
const listInner = useRef(null);
2320
const prevScrollTop = useRef(0);
24-
const created = useRef(false);
21+
const [scrollTop, setscrollTop] = useState(0);
22+
const [listSize, setlistSize] = useState(props.listSize || 1000);
2523
//
26-
const update = () => {
27-
if (created.current) {
28-
scrollTop = list.current!.scrollTop
29-
listSize = list.current!.clientHeight
30-
}
31-
const totalSpace = itemSize * count
32-
let topSpace = scrollTop - buffer
33-
let bottomSpace = totalSpace - scrollTop - listSize - buffer
34-
let startIndex, endIndex
24+
const totalSpace = itemSize * count
25+
let topSpace = scrollTop - buffer
26+
let bottomSpace = totalSpace - scrollTop - listSize - buffer
27+
let startIndex, endIndex
3528

36-
if (topSpace <= 0) {
37-
topSpace = 0
38-
startIndex = 0
39-
} else {
40-
startIndex = Math.floor(topSpace / itemSize)
41-
}
42-
if (totalSpace <= listSize) {
43-
endIndex = count
44-
} else {
45-
endIndex = count - Math.floor(bottomSpace / itemSize)
46-
}
47-
if (bottomSpace < 0) {
48-
bottomSpace = 0
49-
}
50-
const visible = props.items.slice(startIndex, endIndex)
51-
let listInnerStyle = { paddingTop: `${topSpace}px`, boxSizing: 'border-box' }
52-
if (bottomSpace < itemSize * 5) {
53-
listInnerStyle['paddingBottom'] = `${bottomSpace}px`
54-
} else {
55-
listInnerStyle['height'] = `${totalSpace}px`
56-
}
57-
setvisible(visible)
58-
setlistInnerStyle(listInnerStyle)
29+
if (topSpace <= 0) {
30+
topSpace = 0
31+
startIndex = 0
32+
} else {
33+
startIndex = Math.floor(topSpace / itemSize)
34+
}
35+
if (totalSpace <= listSize) {
36+
endIndex = count
37+
} else {
38+
endIndex = count - Math.floor(bottomSpace / itemSize)
5939
}
60-
// on created
61-
if (!created.current) {
62-
update()
63-
created.current = true;
40+
if (bottomSpace < 0) {
41+
bottomSpace = 0
6442
}
43+
const visible = props.items.slice(startIndex, endIndex)
44+
const listInnerStyle = { paddingTop: `${topSpace}px`, boxSizing: 'border-box' }
45+
if (bottomSpace < itemSize * 5) {
46+
listInnerStyle['paddingBottom'] = `${bottomSpace}px`
47+
} else {
48+
listInnerStyle['height'] = `${totalSpace}px`
49+
}
50+
useEffect(() => {
51+
setlistSize(list.current!.clientHeight)
52+
if (props.itemSize == null) {
53+
// get avg item size
54+
let count = 0
55+
let totalHeight = 0
56+
for (const el of listInner.current.children) {
57+
const style = getComputedStyle(el)
58+
totalHeight += el.offsetHeight + parseFloat(style.marginTop) + parseFloat(style.marginBottom)
59+
count++
60+
}
61+
setitemSize(totalHeight / count)
62+
}
63+
}, [props.itemSize, props.items]);
64+
//
6565
const handleScroll = () => {
66-
scrollTop = list.current!.scrollTop
67-
if (Math.abs(prevScrollTop.current - scrollTop) > itemSize) {
68-
update()
69-
prevScrollTop.current = scrollTop
66+
setlistSize(list.current!.clientHeight)
67+
const scrollTop2 = list.current!.scrollTop
68+
if (Math.abs(prevScrollTop.current - scrollTop2) > itemSize) {
69+
setscrollTop(scrollTop2)
70+
prevScrollTop.current = scrollTop2
7071
}
7172
}
7273
//
73-
useEffect(() => {
74-
update()
75-
}, []);
76-
//
7774
return <div ref={list} onScroll={handleScroll} style={{ height: '500px', overflow: 'auto', }}>
78-
<div style={listInnerStyle}>
75+
<div ref={listInner} style={{ display: 'flex', flexDirection: 'column', ...listInnerStyle }}>
7976
{visible.map((item, i) => <div key={item.id}>{item.text}</div>)}
8077
</div>
8178
</div>

0 commit comments

Comments
 (0)