@@ -18,14 +18,18 @@ 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 ( ( ) => {
@@ -35,64 +39,55 @@ export default function useNoticeTimer(
3539
3640 const onResume = React . useCallback ( ( ) => {
3741 if ( durationMs > 0 ) {
42+ lastRafTimeRef . current = Date . now ( ) ;
3843 setWalking ( true ) ;
3944 } else {
4045 onEventUpdate ( 0 ) ;
4146 }
42- } , [ durationMs , onEventUpdate ] ) ;
47+ } , [ durationMs ] ) ;
4348
49+ // Reset when durationMs changed.
4450 React . useEffect ( ( ) => {
45- if ( durationMs <= 0 ) {
46- startTimestampRef . current = null ;
47- onEventUpdate ( 0 ) ;
48- return ;
49- }
50-
51- syncPassTime ( ) ;
52- onEventUpdate ( Math . min ( passTimeRef . current / durationMs , 1 ) ) ;
51+ passTimeRef . current = 0 ;
52+ setWalking ( durationMs > 0 ) ;
53+ } , [ durationMs ] ) ;
5354
55+ // Trigger update when walking changed.
56+ React . useEffect ( ( ) => {
5457 if ( ! walking ) {
55- startTimestampRef . current = null ;
5658 return ;
5759 }
5860
59- if ( passTimeRef . current >= durationMs ) {
60- onEventUpdate ( 1 ) ;
61- onEventClose ( ) ;
62- return ;
63- }
61+ // Use raf to update since it can provide more accurate timing and better performance for animations.
62+ if ( trackProgress ) {
63+ let rafId : number | null = null ;
6464
65- const timeout = window . setTimeout ( ( ) => {
66- passTimeRef . current = durationMs ;
67- onEventUpdate ( 1 ) ;
68- onEventClose ( ) ;
69- } , durationMs - passTimeRef . current ) ;
65+ function step ( ) {
66+ syncPassTime ( ) ;
7067
71- if ( ! trackProgress ) {
72- return ( ) => {
73- window . clearTimeout ( timeout ) ;
74- } ;
75- }
68+ if ( passTimeRef . current >= durationMs ) {
69+ onEventUpdate ( 1 ) ;
70+ onEventClose ( ) ;
71+ } else {
72+ onEventUpdate ( Math . min ( passTimeRef . current / durationMs , 1 ) ) ;
73+ rafId = raf ( step ) ;
74+ }
75+ }
7676
77- let rafId : number | null = null ;
77+ step ( ) ;
7878
79- function step ( ) {
80- syncPassTime ( ) ;
81- onEventUpdate ( Math . min ( passTimeRef . current / durationMs , 1 ) ) ;
79+ return ( ) => {
80+ raf . cancel ( rafId ! ) ;
81+ } ;
82+ } else {
83+ // Fallback to setTimeout when progress tracking is not needed, which can save some resources.
84+ const timeoutId = window . setTimeout ( onEventClose , durationMs ) ;
8285
83- if ( passTimeRef . current < durationMs ) {
84- rafId = raf ( step ) ;
85- }
86+ return ( ) => {
87+ window . clearTimeout ( timeoutId ) ;
88+ } ;
8689 }
87-
88- startTimestampRef . current = Date . now ( ) ;
89- rafId = raf ( step ) ;
90-
91- return ( ) => {
92- window . clearTimeout ( timeout ) ;
93- raf . cancel ( rafId ) ;
94- } ;
95- } , [ durationMs , walking ] ) ;
90+ } , [ walking ] ) ;
9691
9792 return [ onResume , onPause ] as const ;
9893}
0 commit comments