Skip to content

Instantly share code, notes, and snippets.

@joncardasis
Last active July 20, 2022 23:38
Show Gist options
  • Save joncardasis/25914c395dd685fd77f9eeab7b6af6cf to your computer and use it in GitHub Desktop.
Save joncardasis/25914c395dd685fd77f9eeab7b6af6cf to your computer and use it in GitHub Desktop.
Simple SkeletonView react-native component (react-native-reanimated v1.9.0)
import React, { useCallback, useMemo, useRef, useState } from 'react';
import { StyleProp, StyleSheet, View, ViewStyle } from 'react-native';
import LinearGradient from 'react-native-linear-gradient';
import Animated, {
block,
Clock,
cond,
Easing,
eq,
set,
startClock,
timing,
useCode,
Value,
} from 'react-native-reanimated';
const AnimatedLinearGradient = Animated.createAnimatedComponent(LinearGradient);
interface SkeletonViewProps {
colors?: {
primary: string;
highlight: string;
};
style?: StyleProp<ViewStyle>;
}
const SkeletonView: React.FC<SkeletonViewProps> = ({ colors, style }) => {
const animatedValue = useRef(new Value(0)).current;
const clock = useRef(new Clock()).current;
const [width, setWidth] = useState(0);
const primaryColor = useMemo(() => colors?.primary || '#cccccc', [colors]);
const highlightColor = useMemo(() => colors?.highlight || '#c0c0c0', [colors]);
const runTiming = useCallback((clock: Animated.Clock) => {
const state = {
finished: new Value(0),
position: new Value(0),
frameTime: new Value(0),
time: new Value(0),
};
const config = {
toValue: new Value(1),
duration: 1000,
easing: Easing.inOut(Easing.ease),
};
return block([
timing(clock, state, config),
cond(eq(state.finished, 1), [
set(state.finished, 0),
set(state.position, 0),
set(state.frameTime, 0),
set(state.time, 0),
]),
state.position,
]);
}, []);
useCode(() => block([startClock(clock), set(animatedValue, runTiming(clock))]), [clock, animatedValue]);
const translateX = animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [-width, width],
});
return (
<View
style={[
{
height: 100,
backgroundColor: primaryColor,
overflow: 'hidden',
},
style,
]}
onLayout={({ nativeEvent }) => setWidth(nativeEvent.layout.width)}
>
<AnimatedLinearGradient
colors={[primaryColor, highlightColor, highlightColor, primaryColor]}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 0 }}
style={[StyleSheet.absoluteFill, { transform: [{ translateX }] }]}
/>
</View>
);
};
export default SkeletonView;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment