1- import { useCallback , useEffect , useRef , useState } from 'react' ;
2- import TimerWorker from '@/workers/timer.worker?worker' ;
1+ import { useState , useEffect , useCallback } from 'react' ;
32
43interface TimerConfig {
54 initialTime : number ;
@@ -8,85 +7,67 @@ interface TimerConfig {
87}
98
109/**
11- * Web Worker를 활용한 정확한 카운트다운 타이머 커스텀 훅
10+ * 카운트다운 타이머를 관리하는 커스텀 훅입니다.
11+ *
12+ * @description
13+ * 이 훅은 시작 제어 기능을 갖춘 카운트다운 타이머 기능을 제공합니다.
14+ * 초기 시간과 타이머 완료 시 실행될 선택적 콜백을 받습니다.
15+ *
16+ * @example
17+ * ```typescript
18+ * const { time, start } = useTimer({
19+ * initialTime: 60,
20+ * onComplete: () => console.log('타이머 완료!'),
21+ * });
22+ *
23+ * // 타이머 시작
24+ * start();
25+ * ```
1226 *
1327 * @param {TimerConfig } config - 타이머 설정 객체
14- * @returns {object } 타이머 상태와 컨트롤 함수들
28+ * @param {number } config.initialTime - 카운트다운 초기 시간(초 단위)
29+ * @param {() => void } [config.onComplete] - 타이머 완료 시 실행될 선택적 콜백
30+ *
31+ * @returns {object } 현재 시간과 시작 함수를 포함하는 객체
32+ * @returns {number } returns.time - 카운트다운의 현재 시간
33+ * @returns {() => void } returns.start - 타이머를 시작하는 함수
1534 */
35+
1636export const useTimer = ( { initialTime, onComplete } : TimerConfig ) => {
1737 const [ time , setTime ] = useState ( initialTime ) ;
1838 const [ isRunning , setIsRunning ] = useState ( false ) ;
19- const workerRef = useRef < Worker | null > ( null ) ;
2039
2140 useEffect ( ( ) => {
22- // Worker가 이미 존재하면 종료
23- if ( workerRef . current ) {
24- workerRef . current . terminate ( ) ;
25- }
26-
27- // 새 Worker 생성
28- workerRef . current = new TimerWorker ( ) ;
41+ let timer : NodeJS . Timeout | null = null ;
2942
30- // Worker 메시지 핸들러
31- workerRef . current . onmessage = ( event ) => {
32- const { type, payload } = event . data ;
33- // console.log('Received from worker:', type, payload); // 디버깅용
34-
35- switch ( type ) {
36- case 'TICK' :
37- setTime ( payload . time ) ;
38- break ;
39- case 'COMPLETE' :
40- setTime ( 0 ) ;
41- setIsRunning ( false ) ;
42- onComplete ?.( ) ;
43- break ;
44- }
45- } ;
43+ if ( isRunning ) {
44+ timer = setInterval ( ( ) => {
45+ setTime ( ( prev ) => {
46+ const nextTime = prev - 0.1 ;
47+ if ( nextTime <= 0 ) {
48+ setIsRunning ( false ) ;
49+ onComplete ?.( ) ;
50+ return 0 ;
51+ }
52+ return nextTime ;
53+ } ) ;
54+ } , 100 ) ;
55+ }
4656
47- // Clean up
4857 return ( ) => {
49- workerRef . current ?. terminate ( ) ;
58+ if ( timer ) {
59+ clearInterval ( timer ) ;
60+ }
5061 } ;
51- } , [ ] ) ;
62+ } , [ isRunning , onComplete ] ) ;
5263
53- // 타이머 시작
5464 const start = useCallback ( ( ) => {
55- if ( isRunning || ! workerRef . current ) return ;
56-
57- workerRef . current . postMessage ( {
58- type : 'START' ,
59- payload : {
60- duration : initialTime ,
61- serverTime : Date . now ( ) ,
62- } ,
63- } ) ;
64-
65+ if ( isRunning ) return ;
6566 setIsRunning ( true ) ;
66- } , [ isRunning , initialTime ] ) ;
67-
68- // 타이머 정지
69- const stop = useCallback ( ( ) => {
70- if ( ! isRunning || ! workerRef . current ) return ;
71-
72- workerRef . current . postMessage ( { type : 'STOP' } ) ;
73- setIsRunning ( false ) ;
7467 } , [ isRunning ] ) ;
7568
76- // 타이머 리셋
77- const reset = useCallback ( ( ) => {
78- if ( ! workerRef . current ) return ;
79-
80- workerRef . current . postMessage ( { type : 'RESET' } ) ;
81- setTime ( initialTime ) ;
82- setIsRunning ( false ) ;
83- } , [ initialTime ] ) ;
84-
8569 return {
8670 time,
87- isRunning,
8871 start,
89- stop,
90- reset,
9172 } ;
9273} ;
0 commit comments