This is a reusable React Native component for rendering skeleton loaders with customizable dimensions and animations. Skeleton loaders are placeholders used to provide a better user experience while loading content in an application. The component supports both animated and static skeletons, and it can measure the dimensions of a child component to render skeletons with the same dimensions. This component can be useful for improving the perceived performance of your React Native application.
import { useState } from "react"; import { Dimensions, View, Text, Platform } from "react-native" import LinearGradient from "react-native-linear-gradient"; import colors from "../utils/constant/colors"; import Animated, { useAnimatedProps, useFrameCallback, useSharedValue, withTiming } from "react-native-reanimated"; interface SkeltonContainerProps { child: any; childcount?: any; width?: any; height?: any; } interface SkeletonProps { width: number; height: number; marginTop?: number; } const AnimatedLinearGradient = Animated.createAnimatedComponent(LinearGradient); const SkeletonAnimated = ({ width, height, marginTop }: SkeletonProps) => { const locationY = useSharedValue(0); useFrameCallback(() => { if (locationY.value == 1) locationY.value = withTiming(0, { duration: 1000 }); if (locationY.value == 0) locationY.value = withTiming(1, { duration: 1000 }); }); const animatedProps = useAnimatedProps(() => { return { locations: [0, locationY.value] } }) return ( <AnimatedLinearGradient colors={[colors.LightGray, colors.White]} animatedProps={animatedProps} style={{ width: width, height: height, marginTop: marginTop }} /> ) } const SkeletonStatic = ({ width, height, marginTop }: SkeletonProps) => { return ( <LinearGradient colors={[colors.LightGray, colors.White]} style={{ width: width, height: height, marginTop: marginTop }} /> ) } const Skeleton = ({ width = Dimensions.get('window').width, height = 200, marginTop = 0 }: SkeletonProps) => { return ( Platform.OS == 'ios' ? <SkeletonAnimated width={width} height={height} marginTop={marginTop} /> : <SkeletonStatic width={width} height={height} marginTop={marginTop} /> ) } const SkeletonContainer = ({ child, childcount = 1, width = Dimensions.get('window').width, height = 64 }: SkeltonContainerProps) => { const [dimensions, setDimensions] = useState({ width: 0, height: 0 }) return ( child ? <View> <View style={{ opacity: 0 }} onLayout={(event) => setDimensions({ width: event.nativeEvent.layout.width, height: event.nativeEvent.layout.height })}>{child}</View> <Skeleton width={dimensions.width} height={dimensions.height} marginTop={-dimensions.height} /> {[...Array(childcount - 1).keys()].map((index) => <Skeleton key={index} width={dimensions.width} height={dimensions.height} />)} </View> : [...Array(childcount).keys()].map((index) => <Skeleton key={index} width={width} height={height} />) ) } export default SkeletonContainer;
Top comments (0)