This episode covers animation: a comparison of the built-in Animated with worklet-based Reanimated 3+, React Native Gesture Handler, transition patterns, gesture-driven animation, and Lottie for complex animations.

Animation is what distinguishes an app that feels alive from one that feels rigid: imagine a button that responds to touch, a card that follows your finger, or smooth transitions between screens. On mobile, a stuttering animation is the clearest sign an app isn't professional.
Episode 19 covers animation in React Native: the built-in Animated, Reanimated 3+ which executes animations on the UI Thread via worklets, React Native Gesture Handler for touch, transition and gesture-driven animation patterns, plus Lottie for complex animations from design files.
Animated is React Native's built-in API for JS Thread-based animation. It fits simple animations — fade, translate, scale:
import { Animated, View, Text, Pressable } from "react-native";
export function Fade() {
const opacity = new Animated.Value(0);
function muncul() {
Animated.timing(opacity, {
toValue: 1,
duration: 400,
useNativeDriver: true,
}).start();
}
return (
<Animated.View style={{ opacity }}>
<Pressable onPress={muncul}>
<Text>Muncul</Text>
</Pressable>
</Animated.View>
);
}Animated.timing(opacity, { toValue: 1, duration: 400 }) animates the value from 0 to 1 over 400 milliseconds. Always enable useNativeDriver: true so the animation runs natively — it's smoother.
Reanimated introduces worklets: JavaScript functions written in your app but executed on the UI Thread. Animations no longer wait in the JS Thread queue, so they stay smooth even when the app is busy.
Reanimated requires a Babel plugin. Install it and add the plugin to babel.config.js:
npm install react-native-reanimatedplugins: ['react-native-reanimated/plugin']The Babel plugin order matters — the Reanimated plugin must be last so worklets are detected correctly.
Animation values are stored in useSharedValue, and useAnimatedStyle connects them to style:
import Animated, {
useSharedValue,
useAnimatedStyle,
withSpring,
} from "react-native-reanimated";
export function TombolPesan() {
const skala = useSharedValue(1);
const gaya = useAnimatedStyle(() => {
return { transform: [{ scale: skala.value }] };
});
return (
<Animated.View
style={gaya}
onTouchStart={() => (skala.value = withSpring(0.9))}
onTouchEnd={() => (skala.value = withSpring(1))}
>
<Text>Tekan</Text>
</Animated.View>
);
}useAnimatedStyle(() => ({ transform: [{ scale: skala.value }] })) runs as a worklet on the UI Thread. When skala.value changes, the style updates immediately without waiting for the JS Thread. withSpring provides a natural spring effect.
Animated and Pressable only catch simple touches. Gesture Handler recognizes pan, pinch, rotation, and their combinations with high precision, and integrates smoothly with Reanimated:
npm install react-native-gesture-handlerimport { Gesture, GestureDetector } from "react-native-gesture-handler";
import Animated, {
useSharedValue,
useAnimatedStyle,
withTiming,
} from "react-native-reanimated";
export function KartuGeser() {
const x = useSharedValue(0);
const pan = Gesture.Pan()
.onUpdate((e) => (x.value = e.translationX))
.onEnd(() => (x.value = withTiming(0)));
const gaya = useAnimatedStyle(() => ({
transform: [{ translateX: x.value }],
}));
return (
<GestureDetector gesture={pan}>
<Animated.View style={gaya} />
</GestureDetector>
);
}Gesture.Pan() catches finger movement; onUpdate moves the card to follow the finger, and onEnd returns it with a timing animation. The Gesture Handler and Reanimated combination is the standard for swipe, drag, and expandable cards.
Commonly used patterns:
Rule of thumb: animation must mean something — providing context or feedback — not just decoration that slows things down.
For complex icon, loader, or illustration animations created by designers in After Effects, use Lottie. The animation is exported as JSON and rendered natively:
npm install lottie-react-native lottie-iossource={require("./assets/loading.json")} loads the animation file from a local asset, and the autoPlay prop with loop makes it run automatically. Lottie handles complex animations that are hard to rewrite manually with native performance.
Warning
Don't pile up animations on one screen. Many useSharedValues and animations that always run drain battery and memory. Design animations that only run when relevant and stop when not needed.
Episode 19 brought the app to life: the built-in Animated for simple animations, Reanimated 3+ with worklets on the UI Thread, Gesture Handler for precise touch, meaningful motion patterns, and Lottie for complex animations.
Key takeaways:
useSharedValue and useAnimatedStyle are Reanimated's foundation.In the next episode, episode 20, we'll discuss testing and tooling: Jest with React Native Testing Library for unit tests, Detox for E2E, CI/CD with GitHub Actions, Fastlane and EAS Build for distribution, plus over-the-air updates with EAS Update.