+ >
+ );
+}
+
+export const DisplayNone: ListViewStory = {
+ render: (args) => ,
+ name: 'display: none with many items'
+};
diff --git a/packages/@react-spectrum/list/test/ListView.test.js b/packages/@react-spectrum/list/test/ListView.test.js
index 6f4eab54f16..5ab989dfa75 100644
--- a/packages/@react-spectrum/list/test/ListView.test.js
+++ b/packages/@react-spectrum/list/test/ListView.test.js
@@ -1664,4 +1664,28 @@ describe('ListView', function () {
});
});
});
+
+ describe('height 0', () => {
+
+ it('should render and not infinite loop', function () {
+ offsetWidth = jest.spyOn(window.HTMLElement.prototype, 'clientWidth', 'get').mockImplementation(() => 0);
+ offsetHeight = jest.spyOn(window.HTMLElement.prototype, 'clientHeight', 'get').mockImplementation(() => 0);
+ scrollHeight = jest.spyOn(window.HTMLElement.prototype, 'scrollHeight', 'get').mockImplementation(() => 0);
+ let tree = render(
+ ({key: k, name: `Item ${k}`}))}>
+ {item => {item.name}}
+
+ );
+ let grid = tree.getByRole('grid');
+ act(() => {
+ jest.runAllTimers();
+ });
+ expect(grid.firstChild).toBeEmptyDOMElement();
+ });
+ });
});
diff --git a/packages/@react-stately/virtualizer/src/OverscanManager.ts b/packages/@react-stately/virtualizer/src/OverscanManager.ts
index 8e5bf126a2a..a12cc686b87 100644
--- a/packages/@react-stately/virtualizer/src/OverscanManager.ts
+++ b/packages/@react-stately/virtualizer/src/OverscanManager.ts
@@ -17,7 +17,7 @@ export class OverscanManager {
private startTime = 0;
private velocity = new Point(0, 0);
private visibleRect = new Rect();
-
+
setVisibleRect(rect: Rect) {
let time = performance.now() - this.startTime;
if (time < 500) {
diff --git a/packages/@react-stately/virtualizer/src/Virtualizer.ts b/packages/@react-stately/virtualizer/src/Virtualizer.ts
index 7940dcabbdb..36ed878f948 100644
--- a/packages/@react-stately/virtualizer/src/Virtualizer.ts
+++ b/packages/@react-stately/virtualizer/src/Virtualizer.ts
@@ -23,8 +23,8 @@ import {Size} from './Size';
/**
* The Virtualizer class renders a scrollable collection of data using customizable layouts.
- * It supports very large collections by only rendering visible views to the DOM, reusing
- * them as you scroll. Virtualizer can present any type of view, including non-item views
+ * It supports very large collections by only rendering visible views to the DOM, reusing
+ * them as you scroll. Virtualizer can present any type of view, including non-item views
* such as section headers and footers.
*
* Virtualizer uses {@link Layout} objects to compute what views should be visible, and how
@@ -133,7 +133,7 @@ export class Virtualizer {
*/
keyAtPoint(point: Point): Key | null {
let rect = new Rect(point.x, point.y, 1, 1);
- let layoutInfos = this.layout.getVisibleLayoutInfos(rect);
+ let layoutInfos = rect.area === 0 ? [] : this.layout.getVisibleLayoutInfos(rect);
// Layout may return multiple layout infos in the case of
// persisted keys, so find the first one that actually intersects.
@@ -180,7 +180,7 @@ export class Virtualizer {
rect = this._overscanManager.getOverscannedRect();
}
- let layoutInfos = this.layout.getVisibleLayoutInfos(rect);
+ let layoutInfos = rect.area === 0 ? [] : this.layout.getVisibleLayoutInfos(rect);
let map = new Map;
for (let layoutInfo of layoutInfos) {
map.set(layoutInfo.key, layoutInfo);
@@ -273,7 +273,7 @@ export class Virtualizer {
if (!this.visibleRect.equals(opts.visibleRect)) {
this._overscanManager.setVisibleRect(opts.visibleRect);
let shouldInvalidate = this.layout.shouldInvalidate(opts.visibleRect, this.visibleRect);
-
+
if (shouldInvalidate) {
offsetChanged = !opts.visibleRect.pointEquals(this.visibleRect);
sizeChanged = !opts.visibleRect.sizeEquals(this.visibleRect);