Skip to content

Commit dd5b7c3

Browse files
authored
fix: cancel stale scroll retry sync
Cancel stale per-target scroll retry timers before scheduling a new retry.
1 parent 7da1f76 commit dd5b7c3

2 files changed

Lines changed: 59 additions & 2 deletions

File tree

src/Table.tsx

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -453,23 +453,36 @@ const Table = <RecordType extends DefaultRecordType>(
453453
}, []);
454454

455455
const [setScrollTarget, getScrollTarget] = useTimeoutLock(null);
456+
const [scrollRetryTimeoutMap] = React.useState(
457+
() => new WeakMap<HTMLDivElement, ReturnType<typeof setTimeout>>(),
458+
);
456459

457460
function forceScroll(scrollLeft: number, target: HTMLDivElement | ((left: number) => void)) {
458461
if (!target) {
459462
return;
460463
}
461464
if (typeof target === 'function') {
462465
target(scrollLeft);
463-
} else if (target.scrollLeft !== scrollLeft) {
466+
return;
467+
}
468+
469+
const scrollRetryTimeout = scrollRetryTimeoutMap.get(target);
470+
if (scrollRetryTimeout) {
471+
clearTimeout(scrollRetryTimeout);
472+
}
473+
474+
if (target.scrollLeft !== scrollLeft) {
464475
target.scrollLeft = scrollLeft;
465476

466477
// Delay to force scroll position if not sync
467478
// ref: https://github.com/ant-design/ant-design/issues/37179
468-
setTimeout(() => {
479+
const retryTimeout = setTimeout(() => {
469480
if (target.scrollLeft !== scrollLeft) {
470481
target.scrollLeft = scrollLeft;
471482
}
472483
}, 0);
484+
485+
scrollRetryTimeoutMap.set(target, retryTimeout);
473486
}
474487
}
475488

tests/Table.spec.jsx

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1365,4 +1365,48 @@ describe('Table.Basic', () => {
13651365
vi.useRealTimers();
13661366
}
13671367
});
1368+
1369+
it('cancels stale scrollLeft retry when target already synced', () => {
1370+
vi.useFakeTimers();
1371+
1372+
try {
1373+
const { container } = render(
1374+
createTable({
1375+
scroll: { x: 100, y: 100 },
1376+
}),
1377+
);
1378+
1379+
const tableHeader = container.querySelector('.rc-table-header');
1380+
const tableBody = container.querySelector('.rc-table-body');
1381+
let headerScrollLeft = 0;
1382+
let bodyScrollLeft = 0;
1383+
1384+
Object.defineProperty(tableHeader, 'scrollLeft', {
1385+
get() {
1386+
return headerScrollLeft;
1387+
},
1388+
set(value) {
1389+
headerScrollLeft = value;
1390+
},
1391+
});
1392+
Object.defineProperty(tableBody, 'scrollLeft', {
1393+
get() {
1394+
return bodyScrollLeft;
1395+
},
1396+
});
1397+
1398+
bodyScrollLeft = 100;
1399+
fireEvent.scroll(tableBody);
1400+
1401+
headerScrollLeft = 50;
1402+
bodyScrollLeft = 50;
1403+
fireEvent.scroll(tableBody);
1404+
1405+
vi.runAllTimers();
1406+
1407+
expect(headerScrollLeft).toBe(50);
1408+
} finally {
1409+
vi.useRealTimers();
1410+
}
1411+
});
13681412
});

0 commit comments

Comments
 (0)