I have implemented a hook in my react native project in order to have all my skeletons for different components in one file as they all use the same animation style
const useColorAnimation = () => {
const { themeColors, accentColor } = useTheme();
const colorAnimation = useRef(new Animated.Value(0)).current;
const [interpolatedColor, setInterpolatedColor] = useState<any>(themeColors?.secondaryBackground);
const startColorAnimation = () => {
Animated.loop(
Animated.sequence([
Animated.timing(colorAnimation, {
toValue: 1,
duration: 500,
easing: Easing.linear,
useNativeDriver: false,
}),
Animated.timing(colorAnimation, {
toValue: 0,
duration: 500,
easing: Easing.linear,
useNativeDriver: false,
}),
])
).start();
};
useEffect(() => {
startColorAnimation();
colorAnimation.addListener(() => {
setInterpolatedColor(
colorAnimation.interpolate({
inputRange: [0, 1],
outputRange: [themeColors?.secondaryBackground, themeColors?.primaryBackground],
})
);
});
return () => {
colorAnimation.removeAllListeners();
};
}, []);
return { interpolatedColor, themeColors, accentColor };
};
export const DiscoveryCardSkeletons = () => {
// eslint-disable-next-line no-unused-vars
const { interpolatedColor, themeColors, accentColor } = useColorAnimation();
const containerStyleDiscovery: ViewStyle = {
margin: 10,
height: 170,
width: 120,
marginRight: 10,
borderRadius: 10,
backgroundColor: interpolatedColor,
};
const containerStyleCommunity: ViewStyle = {
borderRadius: 16,
width: 170,
height: 150,
marginHorizontal: 10,
marginBottom: 16,
backgroundColor: interpolatedColor,
};
const discussionPostStyle: ViewStyle = {
width: '100%',
height: 209,
backgroundColor: themeColors?.secondaryBackground,
marginBottom: 10,
};
const communityStyle: ViewStyle = {
width: 60,
height: 60,
backgroundColor: interpolatedColor,
marginBottom: 5,
borderRadius: 12,
};
const playlistsStyle: ViewStyle = {
height: 130,
width: 130,
backgroundColor: interpolatedColor,
marginBottom: 5,
borderRadius: 10,
};
const playlistsTitleStyle: ViewStyle = {
height: 30,
width: 130,
backgroundColor: interpolatedColor,
borderRadius: 10,
};
const performanceMetricsSkeleton: ViewStyle = {
justifyContent: 'flex-start',
alignItems: 'center',
width: '46%',
marginBottom: 12,
marginHorizontal: '2%',
borderRadius: 10,
paddingVertical: 10,
paddingHorizontal: 5,
shadowColor: themeColors?.primaryShadow,
height: 62,
backgroundColor: interpolatedColor,
};
const PerformanceMetricsSkeleton = () => <Animated.View style={performanceMetricsSkeleton} />;
const PlaylistsSkeleton = () => (
<View>
<Animated.View style={playlistsStyle} />
<Animated.View style={playlistsTitleStyle} />
</View>
);
const CardRowSkeleton = () => <Animated.View style={containerStyleDiscovery} />;
const CardGridSkeleton = () => <Animated.View style={containerStyleCommunity} />;
const DiscussionPostSkeleton = () => (
<View style={discussionPostStyle}>
<View
style={{
padding: 12,
paddingBottom: 0,
flexDirection: 'row',
alignItems: 'center',
flex: 1,
}}
>
<Animated.View
style={{
width: 50,
height: 50,
borderRadius: 100,
backgroundColor: interpolatedColor,
}}
/>
<View
style={{
paddingHorizontal: 12,
flexDirection: 'row',
overflow: 'scroll',
height: 64,
}}
>
<View>
<Animated.View
style={{
height: 12,
width: 70,
borderRadius: 4,
marginBottom: 10,
backgroundColor: interpolatedColor,
}}
/>
<Animated.View
style={{
height: 12,
width: 120,
borderRadius: 4,
marginBottom: 10,
backgroundColor: interpolatedColor,
}}
/>
<Animated.View
style={{
height: 12,
width: 90,
borderRadius: 4,
backgroundColor: interpolatedColor,
}}
/>
</View>
</View>
<View
style={{
flexDirection: 'row',
flex: 1,
justifyContent: 'flex-end',
alignItems: 'center',
}}
>
<Animated.View
style={{
width: 74,
height: 36,
borderRadius: 8,
backgroundColor: interpolatedColor,
}}
/>
<ThreeDotsVertical height={30} width={30} />
</View>
</View>
<View
style={{
justifyContent: 'center',
paddingHorizontal: 12,
flex: 1,
}}
>
<Animated.View
style={{
width: '60%',
height: 14,
borderRadius: 4,
backgroundColor: interpolatedColor,
}}
/>
</View>
<View
style={{
paddingHorizontal: 12,
flexDirection: 'row',
marginBottom: 10,
justifyContent: 'space-between',
}}
>
<View
style={{
flexDirection: 'row',
alignItems: 'center',
}}
>
<View
style={{
alignItems: 'center',
flexDirection: 'row',
}}
>
<Animated.View
style={{
width: 20,
height: 20,
borderRadius: 100,
backgroundColor: interpolatedColor,
}}
/>
<Animated.View
style={{
width: 20,
height: 20,
borderRadius: 100,
backgroundColor: interpolatedColor,
marginLeft: -5,
}}
/>
</View>
<View
style={{
flexDirection: 'row',
alignItems: 'center',
marginLeft: 5,
}}
>
<Animated.View
style={{
width: 50,
height: 14,
borderRadius: 4,
backgroundColor: interpolatedColor,
}}
/>
</View>
</View>
<View style={{ flexDirection: 'row' }}>
<View
style={{
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
}}
>
<Animated.View
style={{
width: 8,
height: 12,
borderRadius: 2,
backgroundColor: interpolatedColor,
marginRight: 1,
}}
/>
<Typography
text="Comments •"
typographyStyle="SmallCopy"
textColor={themeColors?.secondaryText}
/>
</View>
<View
style={{
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
}}
>
<Animated.View
style={{
width: 8,
height: 12,
borderRadius: 2,
backgroundColor: interpolatedColor,
marginRight: 1,
}}
/>
<Typography
text="Reposts"
typographyStyle="SmallCopy"
textColor={themeColors?.secondaryText}
/>
</View>
</View>
</View>
<View
style={{
flexDirection: 'row',
justifyContent: 'space-evenly',
paddingTop: 12,
alignItems: 'center',
borderTopWidth: 0.2,
borderTopColor: themeColors?.secondaryText,
marginBottom: 12,
}}
>
{/* LIKES */}
<View
style={{
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
position: 'relative',
}}
>
<LikeIcon color={themeColors?.primaryText} width={24} height={24} />
<Typography
text="Like"
typographyStyle="SmallCopy"
textColor={themeColors?.secondaryText}
/>
</View>
{/* COMMENTS */}
<View
style={{
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
}}
>
<View style={{ marginRight: 5 }}>
<CommentBubbleWithDots color={themeColors?.secondaryText} />
</View>
<Typography
text="Comment"
typographyStyle="SmallCopy"
textColor={themeColors?.secondaryText}
/>
</View>
{/* SHARES */}
<View
style={{
flexDirection: 'row',
}}
>
<ShareIcon color={themeColors?.secondaryText} />
<View style={{ marginLeft: 5 }}>
<Typography
text="Share"
typographyStyle="SmallCopy"
textColor={themeColors?.secondaryText}
/>
</View>
</View>
</View>
</View>
);
const CommunitiesSkeleton = () => (
<View
style={{
width: 100,
height: 116,
justifyContent: 'center',
alignItems: 'center',
}}
>
<Animated.View style={communityStyle} />
<View
style={{
alignItems: 'center',
}}
>
<Animated.View
style={{
width: 65,
height: 12,
borderRadius: 4,
backgroundColor: interpolatedColor,
marginBottom: 4,
}}
/>
<Animated.View
style={{
width: 75,
height: 10,
backgroundColor: interpolatedColor,
borderRadius: 4,
}}
/>
</View>
</View>
);
const discoverArr = [1, 2, 3, 4, 5, 6];
return {
PlaylistsSkeleton,
PerformanceMetricsSkeleton,
CardRowSkeleton,
CardGridSkeleton,
DiscussionPostSkeleton,
CommunitiesSkeleton,
discoverArr,
};
};
when using the debug console even though the page doesnt crash or give me an error for an infinite loop if I console log something i notice that the console log is infinite to the speed of the pulsing effect