11import type { VariantProps } from '@gluestack-ui/nativewind-utils' ;
2- import React , { forwardRef } from 'react' ;
2+ import React , { forwardRef , useEffect , useRef } from 'react' ;
33import { Animated , Easing , Platform , View } from 'react-native' ;
44
55import { skeletonStyle , skeletonTextStyle } from './styles' ;
@@ -18,34 +18,48 @@ type ISkeletonTextProps = React.ComponentProps<typeof View> &
1818 } ;
1919
2020const Skeleton = forwardRef < React . ElementRef < typeof View > , ISkeletonProps > ( ( { className, variant, children, startColor = 'bg-background-200' , isLoaded = false , speed = 2 , ...props } , ref ) => {
21- const pulseAnim = new Animated . Value ( 1 ) ;
21+ const pulseAnim = useRef ( new Animated . Value ( 1 ) ) . current ;
22+ const animRef = useRef < Animated . CompositeAnimation | null > ( null ) ;
2223 const customTimingFunction = Easing . bezier ( 0.4 , 0 , 0.6 , 1 ) ;
2324 const fadeDuration = 0.6 ;
24- const animationDuration = ( fadeDuration * 10000 ) / speed ; // Convert seconds to milliseconds
25+ const animationDuration = ( fadeDuration * 10000 ) / speed ;
2526
26- const pulse = Animated . sequence ( [
27- Animated . timing ( pulseAnim , {
28- toValue : 1 , // Start with opacity 1
29- duration : animationDuration / 2 , // Third of the animation duration
30- easing : customTimingFunction ,
31- useNativeDriver : Platform . OS !== 'web' ,
32- } ) ,
33- Animated . timing ( pulseAnim , {
34- toValue : 0.75 ,
35- duration : animationDuration / 2 , // Third of the animation duration
36- easing : customTimingFunction ,
37- useNativeDriver : Platform . OS !== 'web' ,
38- } ) ,
39- Animated . timing ( pulseAnim , {
40- toValue : 1 ,
41- duration : animationDuration / 2 , // Third of the animation duration
42- easing : customTimingFunction ,
43- useNativeDriver : Platform . OS !== 'web' ,
44- } ) ,
45- ] ) ;
27+ useEffect ( ( ) => {
28+ if ( ! isLoaded ) {
29+ const pulse = Animated . sequence ( [
30+ Animated . timing ( pulseAnim , {
31+ toValue : 1 ,
32+ duration : animationDuration / 2 ,
33+ easing : customTimingFunction ,
34+ useNativeDriver : Platform . OS !== 'web' ,
35+ } ) ,
36+ Animated . timing ( pulseAnim , {
37+ toValue : 0.75 ,
38+ duration : animationDuration / 2 ,
39+ easing : customTimingFunction ,
40+ useNativeDriver : Platform . OS !== 'web' ,
41+ } ) ,
42+ Animated . timing ( pulseAnim , {
43+ toValue : 1 ,
44+ duration : animationDuration / 2 ,
45+ easing : customTimingFunction ,
46+ useNativeDriver : Platform . OS !== 'web' ,
47+ } ) ,
48+ ] ) ;
49+ animRef . current = Animated . loop ( pulse ) ;
50+ animRef . current . start ( ) ;
51+ } else {
52+ animRef . current ?. stop ( ) ;
53+ animRef . current = null ;
54+ }
55+
56+ return ( ) => {
57+ animRef . current ?. stop ( ) ;
58+ animRef . current = null ;
59+ } ;
60+ } , [ isLoaded , animationDuration , pulseAnim , customTimingFunction ] ) ;
4661
4762 if ( ! isLoaded ) {
48- Animated . loop ( pulse ) . start ( ) ;
4963 return (
5064 < Animated . View
5165 style = { { opacity : pulseAnim } }
@@ -58,8 +72,6 @@ const Skeleton = forwardRef<React.ElementRef<typeof View>, ISkeletonProps>(({ cl
5872 />
5973 ) ;
6074 } else {
61- Animated . loop ( pulse ) . stop ( ) ;
62-
6375 return children ;
6476 }
6577} ) ;
0 commit comments