@@ -409,7 +409,21 @@ export class Virtualizer<
409409 return ( _ro = new this . targetWindow . ResizeObserver ( ( entries ) => {
410410 entries . forEach ( ( entry ) => {
411411 const run = ( ) => {
412- this . _measureElement ( entry . target as TItemElement , entry )
412+ const node = entry . target as TItemElement
413+ const index = this . indexFromElement ( node )
414+
415+ if ( ! node . isConnected ) {
416+ this . observer . unobserve ( node )
417+ this . elementsCache . delete ( this . options . getItemKey ( index ) )
418+ return
419+ }
420+
421+ if ( this . shouldMeasureDuringScroll ( index ) ) {
422+ this . resizeItem (
423+ index ,
424+ this . options . measureElement ( node , entry , this ) ,
425+ )
426+ }
413427 }
414428 this . options . useAnimationFrameWithResizeObserver
415429 ? requestAnimationFrame ( run )
@@ -984,21 +998,19 @@ export class Virtualizer<
984998 return true
985999 }
9861000
987- private _measureElement = (
988- node : TItemElement ,
989- entry : ResizeObserverEntry | undefined ,
990- ) => {
991- if ( ! node . isConnected ) {
992- this . observer . unobserve ( node )
1001+ measureElement = ( node : TItemElement | null ) => {
1002+ if ( ! node ) {
1003+ this . elementsCache . forEach ( ( cached , key ) => {
1004+ if ( ! cached . isConnected ) {
1005+ this . observer . unobserve ( cached )
1006+ this . elementsCache . delete ( key )
1007+ }
1008+ } )
9931009 return
9941010 }
9951011
9961012 const index = this . indexFromElement ( node )
997- const item = this . measurementsCache [ index ]
998- if ( ! item ) {
999- return
1000- }
1001- const key = item . key
1013+ const key = this . options . getItemKey ( index )
10021014 const prevNode = this . elementsCache . get ( key )
10031015
10041016 if ( prevNode !== node ) {
@@ -1009,16 +1021,21 @@ export class Virtualizer<
10091021 this . elementsCache . set ( key , node )
10101022 }
10111023
1012- if ( this . shouldMeasureDuringScroll ( index ) ) {
1013- this . resizeItem ( index , this . options . measureElement ( node , entry , this ) )
1024+ // Sync-measure when idle (initial render) or during programmatic scrolling
1025+ // (scrollToIndex/scrollToOffset) where reconcileScroll needs sizes in the same frame.
1026+ // During normal user scrolling, skip sync measurement — the RO callback handles it async.
1027+ if (
1028+ ( ! this . isScrolling || this . scrollState ) &&
1029+ this . shouldMeasureDuringScroll ( index )
1030+ ) {
1031+ this . resizeItem ( index , this . options . measureElement ( node , undefined , this ) )
10141032 }
10151033 }
10161034
10171035 resizeItem = ( index : number , size : number ) => {
10181036 const item = this . measurementsCache [ index ]
1019- if ( ! item ) {
1020- return
1021- }
1037+ if ( ! item ) return
1038+
10221039 const itemSize = this . itemSizeCache . get ( item . key ) ?? item . size
10231040 const delta = size - itemSize
10241041
@@ -1045,20 +1062,6 @@ export class Virtualizer<
10451062 }
10461063 }
10471064
1048- measureElement = ( node : TItemElement | null | undefined ) => {
1049- if ( ! node ) {
1050- this . elementsCache . forEach ( ( cached , key ) => {
1051- if ( ! cached . isConnected ) {
1052- this . observer . unobserve ( cached )
1053- this . elementsCache . delete ( key )
1054- }
1055- } )
1056- return
1057- }
1058-
1059- this . _measureElement ( node , undefined )
1060- }
1061-
10621065 getVirtualItems = memo (
10631066 ( ) => [ this . getVirtualIndexes ( ) , this . getMeasurements ( ) ] ,
10641067 ( indexes , measurements ) => {
0 commit comments