@@ -18,32 +18,44 @@ export default function useNoticeTimer(
1818 const onEventUpdate = useEvent ( onUpdate ) ;
1919
2020 const [ walking , setWalking ] = React . useState ( durationMs > 0 ) ;
21- const startTimestampRef = React . useRef < number | null > ( null ) ;
2221 const passTimeRef = React . useRef ( 0 ) ;
22+ const lastRafTimeRef = React . useRef < number | null > ( null ) ;
2323
2424 function syncPassTime ( ) {
2525 const now = Date . now ( ) ;
26- const passedTime = now - ( startTimestampRef . current || now ) ;
27- startTimestampRef . current = now ;
28- passTimeRef . current += passedTime ;
26+ const lastRafTime = lastRafTimeRef . current ;
27+
28+ if ( lastRafTime !== null ) {
29+ passTimeRef . current += now - lastRafTime ;
30+ }
31+
32+ lastRafTimeRef . current = now ;
2933 }
3034
3135 const onPause = React . useCallback ( ( ) => {
3236 syncPassTime ( ) ;
37+ if ( durationMs > 0 ) {
38+ onEventUpdate ( Math . min ( passTimeRef . current / durationMs , 1 ) ) ;
39+ }
40+ lastRafTimeRef . current = null ;
3341 setWalking ( false ) ;
34- } , [ ] ) ;
42+ // `onEventUpdate` is a `useEvent` callback and always reads the latest value.
43+ // eslint-disable-next-line react-hooks/exhaustive-deps
44+ } , [ durationMs ] ) ;
3545
3646 const onResume = React . useCallback ( ( ) => {
3747 if ( durationMs > 0 ) {
3848 setWalking ( true ) ;
3949 } else {
4050 onEventUpdate ( 0 ) ;
4151 }
42- } , [ durationMs , onEventUpdate ] ) ;
52+ // `onEventUpdate` is a `useEvent` callback and always reads the latest value.
53+ // eslint-disable-next-line react-hooks/exhaustive-deps
54+ } , [ durationMs ] ) ;
4355
4456 React . useEffect ( ( ) => {
4557 if ( durationMs <= 0 ) {
46- startTimestampRef . current = null ;
58+ lastRafTimeRef . current = null ;
4759 onEventUpdate ( 0 ) ;
4860 return ;
4961 }
@@ -52,7 +64,7 @@ export default function useNoticeTimer(
5264 onEventUpdate ( Math . min ( passTimeRef . current / durationMs , 1 ) ) ;
5365
5466 if ( ! walking ) {
55- startTimestampRef . current = null ;
67+ lastRafTimeRef . current = null ;
5668 return ;
5769 }
5870
@@ -62,6 +74,8 @@ export default function useNoticeTimer(
6274 return ;
6375 }
6476
77+ lastRafTimeRef . current = Date . now ( ) ;
78+
6579 const timeout = window . setTimeout ( ( ) => {
6680 passTimeRef . current = durationMs ;
6781 onEventUpdate ( 1 ) ;
@@ -85,14 +99,15 @@ export default function useNoticeTimer(
8599 }
86100 }
87101
88- startTimestampRef . current = Date . now ( ) ;
89102 rafId = raf ( step ) ;
90103
91104 return ( ) => {
92105 window . clearTimeout ( timeout ) ;
93106 raf . cancel ( rafId ) ;
94107 } ;
95- } , [ durationMs , walking ] ) ;
108+ // `useEvent` callbacks and refs always read latest values.
109+ // eslint-disable-next-line react-hooks/exhaustive-deps
110+ } , [ durationMs , trackProgress , walking ] ) ;
96111
97112 return [ onResume , onPause ] as const ;
98113}
0 commit comments