Skip to content

Commit dfb647a

Browse files
Azir-11honghuangdc
authored andcommitted
fix(hooks): refactor useCountDown hook for improved countdown logic and clarity.
1 parent 7fb5c72 commit dfb647a

File tree

1 file changed

+35
-16
lines changed

1 file changed

+35
-16
lines changed

packages/hooks/src/use-count-down.ts

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,40 +2,59 @@ import { computed, onScopeDispose, ref } from 'vue';
22
import { useRafFn } from '@vueuse/core';
33

44
/**
5-
* count down
5+
* A hook for implementing a countdown timer. It uses `requestAnimationFrame` for smooth and accurate timing,
6+
* independent of the screen refresh rate.
67
*
7-
* @param seconds - count down seconds
8+
* @param initialSeconds - The total number of seconds for the countdown.
89
*/
9-
export default function useCountDown(seconds: number) {
10-
const FPS_PER_SECOND = 60;
10+
export default function useCountDown(initialSeconds: number) {
11+
const remainingSeconds = ref(0);
1112

12-
const fps = ref(0);
13+
const count = computed(() => Math.ceil(remainingSeconds.value));
1314

14-
const count = computed(() => Math.ceil(fps.value / FPS_PER_SECOND));
15-
16-
const isCounting = computed(() => fps.value > 0);
15+
const isCounting = computed(() => remainingSeconds.value > 0);
1716

1817
const { pause, resume } = useRafFn(
19-
() => {
20-
if (fps.value > 0) {
21-
fps.value -= 1;
22-
} else {
18+
({ delta }) => {
19+
// delta: milliseconds elapsed since the last frame.
20+
21+
// If countdown already reached zero or below, ensure it's 0 and stop.
22+
if (remainingSeconds.value <= 0) {
23+
remainingSeconds.value = 0;
24+
pause();
25+
return;
26+
}
27+
28+
// Calculate seconds passed since the last frame.
29+
const secondsPassed = delta / 1000;
30+
remainingSeconds.value -= secondsPassed;
31+
32+
// If countdown has finished after decrementing.
33+
if (remainingSeconds.value <= 0) {
34+
remainingSeconds.value = 0;
2335
pause();
2436
}
2537
},
26-
{ immediate: false }
38+
{ immediate: false } // The timer does not start automatically.
2739
);
2840

29-
function start(updateSeconds: number = seconds) {
30-
fps.value = FPS_PER_SECOND * updateSeconds;
41+
/**
42+
* Starts the countdown.
43+
*
44+
* @param [updatedSeconds=initialSeconds] - Optionally, start with a new duration. Default is `initialSeconds`
45+
*/
46+
function start(updatedSeconds: number = initialSeconds) {
47+
remainingSeconds.value = updatedSeconds;
3148
resume();
3249
}
3350

51+
/** Stops the countdown and resets the remaining time to 0. */
3452
function stop() {
35-
fps.value = 0;
53+
remainingSeconds.value = 0;
3654
pause();
3755
}
3856

57+
// Ensure the rAF loop is cleaned up when the component is unmounted.
3958
onScopeDispose(() => {
4059
pause();
4160
});

0 commit comments

Comments
 (0)