Skip to content

Commit 158a70e

Browse files
authored
fix: Dynamic height bump the scroll pos in some edge case (#309)
* fix: scroll open * chore: adjust logic
1 parent 65777c0 commit 158a70e

File tree

3 files changed

+77
-8
lines changed

3 files changed

+77
-8
lines changed

src/List.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -278,10 +278,12 @@ export function RawList<T>(props: ListProps<T>, ref: React.Ref<ListRef>) {
278278
React.useLayoutEffect(() => {
279279
const changedRecord = heights.getRecord();
280280
if (changedRecord.size === 1) {
281-
const recordKey = Array.from(changedRecord)[0];
281+
const recordKey = Array.from(changedRecord.keys())[0];
282+
const prevCacheHeight = changedRecord.get(recordKey);
283+
282284
// Quick switch data may cause `start` not in `mergedData` anymore
283285
const startItem = mergedData[start];
284-
if (startItem) {
286+
if (startItem && prevCacheHeight === undefined) {
285287
const startIndexKey = getKey(startItem);
286288
if (startIndexKey === recordKey) {
287289
const realStartHeight = heights.get(recordKey);

src/utils/CacheMap.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,18 @@ class CacheMap {
88
// `useMemo` no need to update if `id` not change
99
id: number = 0;
1010

11-
diffKeys = new Set<React.Key>();
11+
diffRecords = new Map<React.Key, number>();
1212

1313
constructor() {
1414
this.maps = Object.create(null);
1515
}
1616

1717
set(key: React.Key, value: number) {
18+
// Record prev value
19+
this.diffRecords.set(key, this.maps[key as string]);
20+
1821
this.maps[key as string] = value;
1922
this.id += 1;
20-
this.diffKeys.add(key as string);
2123
}
2224

2325
get(key: React.Key) {
@@ -29,11 +31,11 @@ class CacheMap {
2931
* To help to know what's update in the next render.
3032
*/
3133
resetRecord() {
32-
this.diffKeys.clear();
34+
this.diffRecords.clear();
3335
}
3436

3537
getRecord() {
36-
return this.diffKeys;
38+
return this.diffRecords;
3739
}
3840
}
3941

tests/scroll.test.js

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,16 @@ describe('List.Scroll', () => {
3838
beforeAll(() => {
3939
mockElement = spyElementPrototypes(HTMLElement, {
4040
offsetHeight: {
41-
get: () => 20,
41+
get() {
42+
const height = this.getAttribute('data-height');
43+
return Number(height || 20);
44+
},
4245
},
4346
clientHeight: {
44-
get: () => 100,
47+
get() {
48+
const height = this.getAttribute('data-height');
49+
return Number(height || 100);
50+
},
4551
},
4652
getBoundingClientRect: () => boundingRect,
4753
offsetParent: {
@@ -666,4 +672,63 @@ describe('List.Scroll', () => {
666672
expect(getScrollTop(container)).toEqual(0);
667673
});
668674
});
675+
676+
it('not scroll jump for item height change', async () => {
677+
jest.useFakeTimers();
678+
679+
const onScroll = jest.fn();
680+
681+
const listRef = React.createRef();
682+
const { container } = genList(
683+
{
684+
itemHeight: 10,
685+
height: 100,
686+
data: genData(100),
687+
ref: listRef,
688+
children: ({ id }) => <li data-id={id}>{id}</li>,
689+
onScroll,
690+
},
691+
render,
692+
);
693+
694+
// first render refresh
695+
await act(async () => {
696+
onLibResize([
697+
{
698+
target: container.querySelector('.rc-virtual-list-holder-inner'),
699+
},
700+
]);
701+
702+
await Promise.resolve();
703+
});
704+
705+
await act(async () => {
706+
jest.advanceTimersByTime(1000);
707+
await Promise.resolve();
708+
});
709+
710+
container.querySelector('li[data-id="0"]').setAttribute('data-height', '30');
711+
712+
// Force change first row height
713+
await act(async () => {
714+
boundingRect.height = 110;
715+
716+
onLibResize([
717+
{
718+
target: container.querySelector('.rc-virtual-list-holder-inner'),
719+
},
720+
]);
721+
722+
await Promise.resolve();
723+
});
724+
725+
await act(async () => {
726+
jest.advanceTimersByTime(1000);
727+
await Promise.resolve();
728+
});
729+
730+
expect(onScroll).not.toHaveBeenCalled();
731+
732+
jest.useRealTimers();
733+
});
669734
});

0 commit comments

Comments
 (0)