Skip to content

Commit d1ad312

Browse files
committed
fix: scrollToIndex
1 parent b0d45ed commit d1ad312

File tree

1 file changed

+28
-11
lines changed

1 file changed

+28
-11
lines changed

lib/VirtualList.tsx

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ export const VirtualList = forwardRef(function <ITEM>(
6868
const listInner = useRef<HTMLDivElement>(null);
6969
const prevScrollTop = useRef(0);
7070
const scrollToIndexRef = useRef<{ index: number, block: string }>();
71+
const [shouldScrollToIndex, setshouldScrollToIndex] = useState([]);
7172
const [scrollTop, setscrollTop] = useState(0);
7273
const [listSize, setlistSize] = useState(props.listSize!);
7374
const [forceRerender, setforceRerender] = useState([]); // change value to force rerender
@@ -92,6 +93,10 @@ export const VirtualList = forwardRef(function <ITEM>(
9293
} else {
9394
endIndex = count - Math.floor(bottomSpace / itemSize)
9495
}
96+
if (!props.virtual) {
97+
startIndex = 0
98+
endIndex = props.items.length
99+
}
95100
const mainVisibleIndices = Array.from({ length: endIndex - startIndex }, (_, index) => index + startIndex);
96101
let visibleIndices = mainVisibleIndices.concat(props.persistentIndices || [])
97102
if (props.persistentIndices?.length) {
@@ -128,18 +133,25 @@ export const VirtualList = forwardRef(function <ITEM>(
128133
}
129134
}, [props.itemSize, props.items, forceRerender]);
130135
//
136+
131137
const handleScroll = function (event: unknown) {
132-
if (ignoreScrollOnce.current) {
133-
ignoreScrollOnce.current = false
138+
if (!props.virtual) {
139+
return
140+
}
141+
if (scrollToIndexRef.current) {
134142
return
135143
}
144+
136145
setlistSize(list.current!.clientHeight)
137-
const scrollTop2 = list.current!.scrollTop
138-
if (Math.abs(prevScrollTop.current - scrollTop2) > (props.triggerDistance ?? itemSize)) {
139-
setscrollTop(scrollTop2)
140-
prevScrollTop.current = scrollTop2
141-
} else if (scrollToIndexRef.current) {
142-
setforceRerender([])
146+
147+
if (ignoreScrollOnce.current) {
148+
ignoreScrollOnce.current = false
149+
} else {
150+
const scrollTop = list.current!.scrollTop;
151+
if (Math.abs(prevScrollTop.current - scrollTop) > (props.triggerDistance ?? itemSize)) {
152+
setscrollTop(scrollTop)
153+
prevScrollTop.current = scrollTop
154+
}
143155
}
144156
// @ts-ignore
145157
props.onScroll?.call(this, event)
@@ -151,12 +163,17 @@ export const VirtualList = forwardRef(function <ITEM>(
151163
index,
152164
block
153165
}
154-
list.current!.scrollTop = index * itemSize
166+
const scrollTop = index * itemSize // estimated value
167+
list.current!.scrollTop = scrollTop
168+
setscrollTop(scrollTop)
169+
prevScrollTop.current = scrollTop
170+
setshouldScrollToIndex([]) // ensure re-render but exclude itemSize. setforceRerender will re calculate avg itemSize, so don't use it here.
155171
},
156172
forceUpdate() {
157173
setforceRerender([])
158174
},
159175
}), [itemSize]);
176+
// scrollToIndex
160177
useLayoutEffect(() => {
161178
if (scrollToIndexRef.current) {
162179
const { index, block } = scrollToIndexRef.current;
@@ -169,10 +186,10 @@ export const VirtualList = forwardRef(function <ITEM>(
169186
ignoreScrollOnce.current = true
170187
}
171188
}
172-
}, [visibleIndices])
189+
}, [shouldScrollToIndex])
173190
//
174191
return <div ref={list} onScroll={handleScroll} className={props.className} style={{ overflow: 'auto', ...props.style }}>
175-
<div ref={listInner} style={{ display: 'flex', flexDirection: 'column', ...listInnerStyle }}>
192+
<div ref={listInner} style={{ display: 'flex', flexDirection: 'column', ...(props.virtual && listInnerStyle) }}>
176193
{visible.map((item, i) => props.renderItem(item, visibleIndices[i]))}
177194
</div>
178195
</div>

0 commit comments

Comments
 (0)