@@ -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