@@ -32,7 +32,7 @@ const ClickSpark = ({
3232} : ClickSparkProps ) => {
3333 const canvasRef = useRef < HTMLCanvasElement > ( null ) ;
3434 const sparksRef = useRef < Spark [ ] > ( [ ] ) ;
35- const startTimeRef = useRef < number | null > ( null ) ;
35+ const animationFrameRef = useRef < number | null > ( null ) ;
3636 const prefersReducedMotion = usePrefersReducedMotion ( ) ;
3737 const isCoarsePointer = useIsCoarsePointer ( ) ;
3838 const disableEffects = prefersReducedMotion || isCoarsePointer ;
@@ -83,21 +83,27 @@ const ClickSpark = ({
8383 [ easing ]
8484 ) ;
8585
86- useEffect ( ( ) => {
87- if ( disableEffects ) {
88- return ;
89- }
86+ const draw = useCallback (
87+ ( timestamp : number ) => {
88+ if ( disableEffects ) {
89+ animationFrameRef . current = null ;
90+ return ;
91+ }
9092
91- const canvas = canvasRef . current ;
92- if ( ! canvas ) return ;
93- const ctx = canvas . getContext ( '2d' ) ;
94- if ( ! ctx ) return ;
95- let animationId : number ;
96- const draw = ( timestamp : number ) => {
97- if ( ! startTimeRef . current ) {
98- startTimeRef . current = timestamp ;
93+ const canvas = canvasRef . current ;
94+ if ( ! canvas ) {
95+ animationFrameRef . current = null ;
96+ return ;
9997 }
100- ctx ?. clearRect ( 0 , 0 , canvas . width , canvas . height ) ;
98+
99+ const ctx = canvas . getContext ( '2d' ) ;
100+ if ( ! ctx ) {
101+ animationFrameRef . current = null ;
102+ return ;
103+ }
104+
105+ ctx . clearRect ( 0 , 0 , canvas . width , canvas . height ) ;
106+
101107 sparksRef . current = sparksRef . current . filter ( ( spark : Spark ) => {
102108 const elapsed = timestamp - spark . startTime ;
103109 if ( elapsed >= duration ) {
@@ -111,6 +117,7 @@ const ClickSpark = ({
111117 const y1 = spark . y + distance * Math . sin ( spark . angle ) ;
112118 const x2 = spark . x + ( distance + lineLength ) * Math . cos ( spark . angle ) ;
113119 const y2 = spark . y + ( distance + lineLength ) * Math . sin ( spark . angle ) ;
120+
114121 ctx . strokeStyle = sparkColor ;
115122 ctx . lineWidth = 2 ;
116123 ctx . beginPath ( ) ;
@@ -119,22 +126,43 @@ const ClickSpark = ({
119126 ctx . stroke ( ) ;
120127 return true ;
121128 } ) ;
122- animationId = requestAnimationFrame ( draw ) ;
123- } ;
124- animationId = requestAnimationFrame ( draw ) ;
129+
130+ if ( sparksRef . current . length > 0 ) {
131+ animationFrameRef . current = requestAnimationFrame ( draw ) ;
132+ } else {
133+ animationFrameRef . current = null ;
134+ }
135+ } ,
136+ [ disableEffects , duration , easeFunc , extraScale , sparkColor , sparkRadius , sparkSize ]
137+ ) ;
138+
139+ useEffect ( ( ) => {
140+ if ( ! disableEffects ) {
141+ return ( ) => {
142+ if ( animationFrameRef . current !== null ) {
143+ cancelAnimationFrame ( animationFrameRef . current ) ;
144+ animationFrameRef . current = null ;
145+ }
146+ } ;
147+ }
148+
149+ sparksRef . current = [ ] ;
150+ const canvas = canvasRef . current ;
151+ const ctx = canvas ?. getContext ( '2d' ) ;
152+ ctx ?. clearRect ( 0 , 0 , canvas ?. width ?? 0 , canvas ?. height ?? 0 ) ;
153+
154+ if ( animationFrameRef . current !== null ) {
155+ cancelAnimationFrame ( animationFrameRef . current ) ;
156+ animationFrameRef . current = null ;
157+ }
158+
125159 return ( ) => {
126- cancelAnimationFrame ( animationId ) ;
160+ if ( animationFrameRef . current !== null ) {
161+ cancelAnimationFrame ( animationFrameRef . current ) ;
162+ animationFrameRef . current = null ;
163+ }
127164 } ;
128- } , [
129- sparkColor ,
130- sparkSize ,
131- sparkRadius ,
132- sparkCount ,
133- duration ,
134- easeFunc ,
135- extraScale ,
136- disableEffects ,
137- ] ) ;
165+ } , [ disableEffects ] ) ;
138166
139167 const handleClick = ( e : React . MouseEvent < HTMLDivElement > ) : void => {
140168 if ( disableEffects ) {
@@ -153,6 +181,10 @@ const ClickSpark = ({
153181 startTime : now ,
154182 } ) ) ;
155183 sparksRef . current . push ( ...newSparks ) ;
184+
185+ if ( animationFrameRef . current === null ) {
186+ animationFrameRef . current = requestAnimationFrame ( draw ) ;
187+ }
156188 } ;
157189
158190 return (
0 commit comments