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)