@@ -108,8 +108,6 @@ export function useVirtual({
108108 }
109109
110110 const virtualItems = React . useMemo ( ( ) => {
111- const { scrollOffset } = latestRef . current
112-
113111 const virtualItems = [ ]
114112
115113 for ( let i = startIndex ; i <= endIndex ; i ++ ) {
@@ -118,13 +116,16 @@ export function useVirtual({
118116 const item = {
119117 ...measurement ,
120118 measureRef : el => {
119+ const { scrollOffset } = latestRef . current
120+
121121 if ( el ) {
122122 const { [ sizeKey ] : measuredSize } = el . getBoundingClientRect ( )
123123
124124 if ( measuredSize !== item . size ) {
125125 if ( item . start < scrollOffset ) {
126126 defaultScrollToFn ( scrollOffset + ( measuredSize - item . size ) )
127127 }
128+
128129 setMeasuredCache ( old => ( {
129130 ...old ,
130131 [ i ] : measuredSize ,
@@ -155,11 +156,8 @@ export function useVirtual({
155156 outerSize,
156157 scrollOffset,
157158 scrollOffsetPlusOuterSize,
158- totalSize,
159159 } = latestRef . current
160160
161- offset = Math . max ( 0 , Math . min ( offset , totalSize - outerSize ) )
162-
163161 if ( align === 'auto' ) {
164162 if ( offset <= scrollOffset ) {
165163 align = 'start'
@@ -181,19 +179,15 @@ export function useVirtual({
181179 [ scrollToFn ]
182180 )
183181
184- const scrollToIndex = React . useCallback (
182+ const tryScrollToIndex = React . useCallback (
185183 ( index , { align = 'auto' , ...rest } = { } ) => {
186184 const {
187185 measurements,
188186 scrollOffset,
189187 scrollOffsetPlusOuterSize,
190188 } = latestRef . current
191189
192- const measurement = measurements [ index ]
193-
194- if ( ! measurement ) {
195- return
196- }
190+ const measurement = measurements [ Math . max ( 0 , Math . min ( index , size - 1 ) ) ]
197191
198192 if ( align === 'auto' ) {
199193 if ( measurement . end >= scrollOffsetPlusOuterSize ) {
@@ -211,9 +205,25 @@ export function useVirtual({
211205 : align === 'end'
212206 ? measurement . end
213207 : measurement . start
208+
214209 scrollToOffset ( offset , { align, ...rest } )
215210 } ,
216- [ scrollToOffset ]
211+ [ scrollToOffset , size ]
212+ )
213+
214+ const scrollToIndex = React . useCallback (
215+ ( ...args ) => {
216+ // We do a double request here because of
217+ // dynamic sizes which can cause offset shift
218+ // and end up in the wrong spot. Unfortunately,
219+ // we can't know about those dynamic sizes until
220+ // we try and render them. So double down!
221+ tryScrollToIndex ( ...args )
222+ requestAnimationFrame ( ( ) => {
223+ tryScrollToIndex ( ...args )
224+ } )
225+ } ,
226+ [ tryScrollToIndex ]
217227 )
218228
219229 return {
0 commit comments