Animations are often treated as an optional enhancement in mobile apps. Many developers open a Figma file, inspect layout spacing, apply colors, build screens, and move on — without ever thinking about motion.
But animations are not decoration. They are communication. They guide attention, improve perceived performance, and make the UI feel natural. Without them, interfaces feel abrupt and lifeless.
There are multiple animation libraries in the React Native ecosystem — the built-in Animated API, Moti, LayoutAnimation, and Reanimated. Each works differently and serves different use cases, but in this guide, we’ll focus specifically on the Reanimated library.
Why Developers Should Care About Animations
Animations improve the UX in four major ways:
- They explain UI changes
- They reduce perceived waiting time
- They make transitions smoother and more intuitive
- They create a premium experience that keeps users engaged
Too much animation can slow down devices, especially low-end Android phones. Good animation is subtle, intentional, and efficient.
Why Reanimated?
Reanimated is preferred for modern animation work because it runs animations on the UI thread, not the JavaScript thread.
UI Thread vs JS Thread
┌──────────────────────────┐ ┌───────────────────────────┐
│ JavaScript Thread │ │ UI Thread │
│--------------------------│ │---------------------------│
│ Runs business logic │ │ Draws UI elements │
│ API calls │ │ Handles layout & paint │
│ React state updates │ │ Runs Reanimated frames │
│ Event handlers │ │ 60fps rendering │
└──────────────────────────┘ └───────────────────────────┘
If animations run here → ❌ can stutter (JS thread can get busy)
If animations run here → ✅ smooth, stable, 60fps
This separation between threads is the foundation of Reanimated’s performance model.
1. What an Animation Represents
An animation is simply a value changing over time:
- opacity:
0 → 1 - position:
20px → 0px - scale:
0.9 → 1
2. Shared Values (useSharedValue — Hook)
Shared values are the foundation of Reanimated.
import { useSharedValue } from 'react-native-reanimated';
const opacity = useSharedValue(0.5);
Shared values:
- Live on the UI thread
- Update at 60fps
- Do NOT trigger React re-renders
- Drive animations without JS slowdowns
They’re like animation‑friendly state variables.
3. Timing Animations (withTiming — Animation Function)
opacity.value = withTiming(1, { duration: 400 });
Meaning:
“Animate opacity from current value → 1 in 400ms.”
Used for:
- fades
- sliding transitions
- smooth, predictable motion
4. Spring Animations (withSpring — Animation Function)
scale.value = withSpring(1, { damping: 8, stiffness: 100 });
This creates:
- bounce
- natural easing
- gesture‑friendly interactions
Perfect for:
- button presses
- cards
- playful UI
5. Animated Styles (useAnimatedStyle — Hook)
useAnimatedStyle takes your shared values and turns them into renderable UI styles that the native thread can animate smoothly.
const animatedStyle = useAnimatedStyle(() => ({
opacity: opacity.value,
transform: [
{ translateY: translateY.value },
{ scale: scale.value }
],
}));
Runs on the UI thread and updates without React re-renders.
Putting It All Together
Now that we understand each piece, here’s how they form a complete animation workflow.
Step 1: Create Shared Values
const opacity = useSharedValue(0);
const translateY = useSharedValue(20);
const scale = useSharedValue(0.9);
Step 2: Trigger Animations
useEffect(() => {
opacity.value = withTiming(1, { duration: 400 });
translateY.value = withTiming(0, { duration: 400 });
scale.value = withSpring(1);
}, []);
Step 3: Create Animated Styles
const animatedStyle = useAnimatedStyle(() => ({
opacity: opacity.value,
transform: [
{ translateY: translateY.value },
{ scale: scale.value }
],
}));
Step 4: Apply to UI
<Animated.View style={animatedStyle}>
<Text style={{ fontSize: 28, fontWeight: '600' }}>
Design.
</Text>
</Animated.View>
Animated.View is required for animated styles.
Working Example
Complete Code Example
import React, { useEffect } from 'react';
import { View, Text, TouchableOpacity } from 'react-native';
import Animated, {
useSharedValue,
useAnimatedStyle,
withTiming,
withSpring
} from 'react-native-reanimated';
export default function AnimatedWordCard() {
const opacity = useSharedValue(0);
const translateY = useSharedValue(20);
const scale = useSharedValue(0.9);
useEffect(() => {
opacity.value = withTiming(1, { duration: 400 });
translateY.value = withTiming(0, { duration: 400 });
scale.value = withSpring(1);
}, []);
const animatedStyle = useAnimatedStyle(() => ({
opacity: opacity.value,
transform: [
{ translateY: translateY.value },
{ scale: scale.value }
],
}));
return (
<View style={{
flex: 1,
backgroundColor: "#0D0D0D",
justifyContent: "center",
alignItems: "center",
paddingHorizontal: 20
}}>
<View
style={{
width: "90%",
backgroundColor: "#1A1A1A",
paddingVertical: 50,
borderRadius: 24,
alignItems: "center",
borderColor: "#2A2A2A",
borderWidth: 1
}}
>
<Animated.View style={animatedStyle}>
<Text
style={{
fontSize: 42,
fontWeight: "700",
color: "white",
letterSpacing: 1
}}
>
Design.
</Text>
</Animated.View>
</View>
<TouchableOpacity
style={{
marginTop: 40,
backgroundColor: "#4A6CF7",
paddingVertical: 14,
paddingHorizontal: 50,
borderRadius: 30,
}}
activeOpacity={0.8}
>
<Text style={{ color: "white", fontSize: 18, fontWeight: "600" }}>
Get Started
</Text>
</TouchableOpacity>
</View>
);
}
Do’s and Don’ts for Smooth Animations
✅ Do:
- animate small components
- use
opacityandtransformfor best performance - test UI on low-end Android devices
- keep transitions subtle and intentional
❌ Don’t:
- animate large layout containers
- animate width/height/layout properties
- trigger too many animations at once
- use heavy shadows & blurs
Final Thoughts
This guide covered the core pieces of Reanimated — shared values, timing, springs, and animated styles — and how they work together on the UI thread to create smooth, modern UI motion.
If you want to go deeper, the next step is exploring text animations, gesture-driven UI, sequencing multiple transitions, and advanced performance techniques.

Top comments (0)