Skip to content

Commit 9067574

Browse files
authored
revert(virtual-core): "notify framework when count changes" (#1112)
1 parent c48b2ac commit 9067574

File tree

4 files changed

+45
-7
lines changed

4 files changed

+45
-7
lines changed

.changeset/hungry-buses-shop.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@tanstack/virtual-core': patch
3+
---
4+
5+
revert(virtual-core): "notify framework when count changes" 2542c5a

docs/api/virtualizer.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,9 +136,9 @@ The position where the list is scrolled to on render. This is useful if you are
136136
getItemKey?: (index: number) => Key
137137
```
138138

139-
This function is passed the index of each item and should return a unique key for that item. The default functionality of this function is to return the index of the item, but you should override this when possible to return a unique identifier for each item across the entire set.
139+
This function is passed the index of each item and should return a unique key for that item. The default functionality of this function is to return the index of the item, but you should override this when possible to return a unique identifier for each item across the entire set.
140140

141-
**Important:** In React (and similar reactive frameworks), this function **must be memoized** (e.g., using `useCallback`) to prevent infinite re-render loops that will crash your application. Without memoization, the virtualizer will detect the function reference change on every render and trigger measurement recalculation, which causes another render, creating an infinite loop.
141+
**Note:** The virtualizer automatically invalidates its measurement cache when measurement-affecting options change, ensuring `getTotalSize()` and other measurements return fresh values. While the virtualizer intelligently tracks which options actually affect measurements, it's still better to memoize `getItemKey` (e.g., using `useCallback` in React) to avoid unnecessary recalculations.
142142

143143
### `rangeExtractor`
144144

packages/virtual-core/src/index.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -645,11 +645,6 @@ export class Virtualizer<
645645
},
646646
{
647647
key: false,
648-
skipInitialOnChange: true,
649-
onChange: () => {
650-
// Notify when measurement options change as they affect total size
651-
this.notify(this.isScrolling)
652-
},
653648
},
654649
)
655650

packages/virtual-core/tests/index.test.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,3 +120,41 @@ test('should correctly recalculate lane assignments when lane count changes', ()
120120
}).not.toThrow()
121121
})
122122
})
123+
124+
test('should update getTotalSize() when count option changes (filtering/search)', () => {
125+
const virtualizer = new Virtualizer({
126+
count: 100,
127+
estimateSize: () => 50,
128+
getScrollElement: () => null,
129+
scrollToFn: vi.fn(),
130+
observeElementRect: vi.fn(),
131+
observeElementOffset: vi.fn(),
132+
})
133+
134+
expect(virtualizer.getTotalSize()).toBe(5000) // 100 × 50
135+
136+
// Simulate filtering - reduce count to 20
137+
virtualizer.setOptions({
138+
count: 20,
139+
estimateSize: () => 50,
140+
getScrollElement: () => null,
141+
scrollToFn: vi.fn(),
142+
observeElementRect: vi.fn(),
143+
observeElementOffset: vi.fn(),
144+
})
145+
146+
// getTotalSize() should immediately return updated value (not stale)
147+
expect(virtualizer.getTotalSize()).toBe(1000) // 20 × 50
148+
149+
// Restore full count
150+
virtualizer.setOptions({
151+
count: 100,
152+
estimateSize: () => 50,
153+
getScrollElement: () => null,
154+
scrollToFn: vi.fn(),
155+
observeElementRect: vi.fn(),
156+
observeElementOffset: vi.fn(),
157+
})
158+
159+
expect(virtualizer.getTotalSize()).toBe(5000) // 100 × 50
160+
})

0 commit comments

Comments
 (0)