Skip to content

Commit 2a699df

Browse files
committed
fix hover pause timer
1 parent ce28148 commit 2a699df

2 files changed

Lines changed: 31 additions & 14 deletions

File tree

src/hooks/useNoticeTimer.ts

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,20 @@ export default function useNoticeTimer(
2020
const [walking, setWalking] = React.useState(durationMs > 0);
2121
const startTimestampRef = React.useRef<number | null>(null);
2222
const passTimeRef = React.useRef(0);
23+
const timeoutRef = React.useRef<number | null>(null);
24+
const rafRef = React.useRef<number | null>(null);
25+
26+
const cleanupTimer = React.useCallback(() => {
27+
if (timeoutRef.current !== null) {
28+
window.clearTimeout(timeoutRef.current);
29+
timeoutRef.current = null;
30+
}
31+
32+
if (rafRef.current !== null) {
33+
raf.cancel(rafRef.current);
34+
rafRef.current = null;
35+
}
36+
}, []);
2337

2438
function syncPassTime() {
2539
const now = Date.now();
@@ -30,8 +44,10 @@ export default function useNoticeTimer(
3044

3145
const onPause = React.useCallback(() => {
3246
syncPassTime();
47+
startTimestampRef.current = null;
48+
cleanupTimer();
3349
setWalking(false);
34-
}, []);
50+
}, [cleanupTimer]);
3551

3652
const onResume = React.useCallback(() => {
3753
if (durationMs > 0) {
@@ -62,37 +78,30 @@ export default function useNoticeTimer(
6278
return;
6379
}
6480

65-
const timeout = window.setTimeout(() => {
81+
timeoutRef.current = window.setTimeout(() => {
6682
passTimeRef.current = durationMs;
6783
onEventUpdate(1);
6884
onEventClose();
6985
}, durationMs - passTimeRef.current);
7086

7187
if (!trackProgress) {
72-
return () => {
73-
window.clearTimeout(timeout);
74-
};
88+
return cleanupTimer;
7589
}
7690

77-
let rafId: number | null = null;
78-
7991
function step() {
8092
syncPassTime();
8193
onEventUpdate(Math.min(passTimeRef.current / durationMs, 1));
8294

8395
if (passTimeRef.current < durationMs) {
84-
rafId = raf(step);
96+
rafRef.current = raf(step);
8597
}
8698
}
8799

88100
startTimestampRef.current = Date.now();
89-
rafId = raf(step);
101+
rafRef.current = raf(step);
90102

91-
return () => {
92-
window.clearTimeout(timeout);
93-
raf.cancel(rafId);
94-
};
95-
}, [durationMs, walking]);
103+
return cleanupTimer;
104+
}, [cleanupTimer, durationMs, onEventClose, onEventUpdate, trackProgress, walking]);
96105

97106
return [onResume, onPause] as const;
98107
}

tests/index.test.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ describe('Notification.Basic', () => {
273273
it('continue timing after hover', () => {
274274
const { instance } = renderDemo({
275275
duration: 1,
276+
showProgress: true,
276277
});
277278

278279
act(() => {
@@ -291,10 +292,17 @@ describe('Notification.Basic', () => {
291292

292293
// Mouse in should not remove
293294
fireEvent.mouseEnter(document.querySelector('.rc-notification-notice'));
295+
const pausedProgress = document
296+
.querySelector<HTMLProgressElement>('.rc-notification-notice-progress')
297+
.getAttribute('value');
294298
act(() => {
299+
// Timer cleanup should happen synchronously when hover starts.
295300
vi.advanceTimersByTime(1000);
296301
});
297302
expect(document.querySelector('.test')).toBeTruthy();
303+
expect(
304+
document.querySelector<HTMLProgressElement>('.rc-notification-notice-progress'),
305+
).toHaveAttribute('value', pausedProgress);
298306

299307
// Mouse out should not remove until 500ms later
300308
fireEvent.mouseLeave(document.querySelector('.rc-notification-notice'));

0 commit comments

Comments
 (0)