Skip to content

Commit 2dd5f96

Browse files
authored
fix: Flicker when scrolling virtualizer in and out of view (adobe#9902)
1 parent 246678e commit 2dd5f96

File tree

2 files changed

+12
-5
lines changed

2 files changed

+12
-5
lines changed

packages/react-aria/src/virtualizer/ScrollView.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,8 @@ export function useScrollView(props: ScrollViewProps, ref: RefObject<HTMLElement
9494
viewportSize: new Size(),
9595
scrollEndTime: 0,
9696
scrollTimeout: null as ReturnType<typeof setTimeout> | null,
97-
isScrolling: false
97+
isScrolling: false,
98+
lastVisibleRect: new Rect()
9899
}).current;
99100
let {direction} = useLocale();
100101

@@ -105,15 +106,19 @@ export function useScrollView(props: ScrollViewProps, ref: RefObject<HTMLElement
105106
// their sizes into account for performance reasons. Their scroll positions are accounted for in viewportOffset
106107
// though (due to getBoundingClientRect). This may result in more rows than absolutely necessary being rendered,
107108
// but no more than the entire height of the viewport which is good enough for virtualization use cases.
108-
let visibleRect = allowsWindowScrolling
109+
let visibleRect = allowsWindowScrolling
109110
? new Rect(
110111
state.viewportOffset.x + state.scrollPosition.x,
111112
state.viewportOffset.y + state.scrollPosition.y,
112113
Math.max(0, Math.min(state.size.width - state.viewportOffset.x, state.viewportSize.width)),
113114
Math.max(0, Math.min(state.size.height - state.viewportOffset.y, state.viewportSize.height))
114115
)
115116
: new Rect(state.scrollPosition.x, state.scrollPosition.y, state.size.width, state.size.height);
116-
onVisibleRectChange(visibleRect);
117+
// Don't emit updates if the visible area is zero and the last emitted area was also zero.
118+
if (visibleRect.area > 0 || state.lastVisibleRect.area > 0) {
119+
onVisibleRectChange(visibleRect);
120+
state.lastVisibleRect = visibleRect;
121+
}
117122
}, [state, allowsWindowScrolling, onVisibleRectChange]);
118123

119124
let [isScrolling, setScrolling] = useState(false);

packages/react-stately/src/layout/ListLayout.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,10 @@ export class ListLayout<T, O extends ListLayoutOptions = ListLayoutOptions> exte
193193
let rowHeight = (this.rowSize ?? this.estimatedRowSize ?? DEFAULT_HEIGHT) + this.gap;
194194
// Clone only before mutating
195195
rect = rect.copy();
196-
rect[offsetProperty] = Math.floor(rect[offsetProperty] / rowHeight) * rowHeight;
197-
rect[heightProperty] = Math.ceil(rect[heightProperty] / rowHeight) * rowHeight;
196+
let offset = Math.floor(rect[offsetProperty] / rowHeight) * rowHeight;
197+
let height = rect[heightProperty] + rect[offsetProperty] - offset;
198+
rect[offsetProperty] = offset;
199+
rect[heightProperty] = Math.ceil(height / rowHeight) * rowHeight;
198200
}
199201

200202
// If layout hasn't yet been done for the requested rect, union the

0 commit comments

Comments
 (0)