1. Pengenalan Reanimated 3
React Native Reanimated 3 adalah library animasi canggih yang menjalankan animasi di UI thread (bukan JS thread). Ini menghasilkan animasi yang sangat halus pada 60fps bahkan saat JS thread sibuk.
Reanimated 3 membawa perubahan signifikan: worklet system baru yang lebih cepat, shared values yang lebih fleksibel, dan integrasi mendalam dengan react-native-gesture-handler.
State Updates
JS & UI Thread
60fps rendering
1.1 Instalasi
# Install Reanimated 3
npm install react-native-reanimated
# Untuk Expo (SDK 50+)
npx expo install react-native-reanimated
# Tambahkan babel plugin
# babel.config.js
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: ['react-native-reanimated/plugin'],
};
Plugin Babel Reanimated HARUS menjadi item terakhir dalam daftar plugins. Jika tidak, worklet compilation akan gagal.
2. Shared Values
useSharedValue adalah state yang dapat diakses oleh kedua thread — JS dan UI. Perubahan shared value tidak memicu re-render React, sehingga sangat efisien untuk data animasi.
import { useSharedValue, useAnimatedStyle, withSpring } from 'react-native-reanimated';
import { View, Button } from 'react-native';
function AnimatedBox() {
// Shared value — bisa diakses di JS & UI thread
const offset = useSharedValue(0);
// Animated style — berjalan di UI thread
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ translateX: offset.value }],
}));
return (
);
}
const styles = {
box: { width: 100, height: 100, backgroundColor: 'blue', borderRadius: 10 },
};
2.1 Perbandingan Shared Value vs State
| Aspek | useState | useSharedValue |
|---|---|---|
| Thread | JS Thread | UI Thread |
| Re-render | Ya | Tidak |
| Animasi | Terputus-putus | Halus 60fps |
| Gesture response | Ada delay | Instant |
| Use case | UI state | Animasi & gesture |
3. Worklets
Worklet adalah fungsi JavaScript yang dikompilasi dan dieksekusi di UI thread. Ini memungkinkan logika kompleks berjalan tanpa memblokir UI.
'use worklet';
// Worklet function — runs on UI thread
function customEasing(t) {
'worklet';
return t * t * (3 - 2 * t); // smoothstep
}
// Menggunakan worklet dalam animation
const animatedStyle = useAnimatedStyle(() => {
'worklet';
const progress = withTiming(1, { duration: 500 });
return {
opacity: progress,
transform: [{ scale: customEasing(progress) }],
};
});
// Worklet untuk logging di UI thread
const style = useAnimatedStyle(() => {
'worklet';
console.log('Running on UI thread!');
// runOnJS untuk memanggil JS function dari worklet
runOnJS(trackEvent)('animation_complete');
return { opacity: 1 };
});
Gunakan worklet untuk logika yang harus berjalan di UI thread: kalkulasi animasi, response gesture, dan interpolasi kompleks. Untuk operasi async seperti network call, tetap di JS thread.
4. Integrasi Gesture Handler
Reanimated 3 terintegrasi sempurna dengan react-native-gesture-handler untuk membuat gesture-driven animation yang responsif.
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
import Animated, {
useSharedValue, useAnimatedStyle, withSpring,
} from 'react-native-reanimated';
function DraggableBox() {
const translateX = useSharedValue(0);
const translateY = useSharedValue(0);
const prevX = useSharedValue(0);
const prevY = useSharedValue(0);
const pan = Gesture.Pan()
.onStart(() => {
prevX.value = translateX.value;
prevY.value = translateY.value;
})
.onUpdate((e) => {
translateX.value = prevX.value + e.translationX;
translateY.value = prevY.value + e.translationY;
})
.onEnd(() => {
// Snap back to origin
translateX.value = withSpring(0, { damping: 15 });
translateY.value = withSpring(0, { damping: 15 });
});
const animatedStyle = useAnimatedStyle(() => ({
transform: [
{ translateX: translateX.value },
{ translateY: translateY.value },
],
}));
return (
);
}
4.1 Composing Gestures
// Gabungkan pan + pinch + rotation
const pan = Gesture.Pan().onUpdate((e) => {
translateX.value = e.translationX;
translateY.value = e.translationY;
});
const pinch = Gesture.Pinch().onUpdate((e) => {
scale.value = e.scale;
});
const rotation = Gesture.Rotation().onUpdate((e) => {
rotate.value = e.rotation;
});
// Jalankan bersamaan
const composed = Gesture.Simultaneous(pan, pinch, rotation);
5. Layout Animations
Reanimated 3 mendukung layout animations bawaan untuk enter, exit, dan layout transition — tanpa kode animasi manual.
import Animated, {
FadeIn, FadeOut, SlideInRight, Layout,
BounceIn, ZoomOut,
} from 'react-native-reanimated';
function AnimatedList({ items }) {
return (
(
{item.title}
)}
/>
);
}
// Custom entering animation
const CustomEnter = () => {
'worklet';
return {
initialValues: { transform: [{ scale: 0 }], opacity: 0 },
animations: {
transform: [{ scale: withSpring(1) }],
opacity: withTiming(1, { duration: 300 }),
},
};
};
// Menggunakan custom animation
Custom Enter!
6. Spring Physics & Timing
Reanimated menyediakan berbagai animation function berbasis fisika: withSpring, withTiming, withDecay, dan withDelay.
import Animated, {
withSpring, withTiming, withDecay, withDelay,
useSharedValue, useAnimatedStyle, Easing,
} from 'react-native-reanimated';
// Spring animation — berbasis fisika
offset.value = withSpring(100, {
damping: 10, // Redaman (default: 10)
stiffness: 100, // Kekakuan (default: 100)
mass: 1, // Massa (default: 1)
overshootClamping: false, // Clamp di target
restDisplacementThreshold: 0.01,
restSpeedThreshold: 2,
});
// Timing animation — berbasis kurva
opacity.value = withTiming(1, {
duration: 500,
easing: Easing.bezier(0.25, 0.1, 0.25, 1),
});
// Decay animation — deselerasi natural
velocityX.value = withDecay({
velocity: 200, // Kecepatan awal
clamp: [-200, 200], // Batas bawah & atas
deceleration: 0.997, // Faktor deselerasi
});
// Delay + sequence
offset.value = withDelay(
500, // Delay 500ms
withSpring(200)
);
| Fungsi | Tipe | Karakteristik |
|---|---|---|
| withSpring | Fisika | Realistis, ada bounce/overshoot |
| withTiming | Kurva | Presisi, kurva halus |
| withDecay | Deselerasi | Scroll momentum, swipe |
| withDelay | Komposer | Menunda animasi berikutnya |
Gunakan withSpring untuk interaksi user (gesture, tap) karena terasa natural. Gunakan withTiming untuk animasi UI yang presisi seperti fade dan slide transition.
7. Scroll-based Animations
import Animated, {
useAnimatedScrollHandler, useAnimatedStyle, interpolate, Extrapolation,
} from 'react-native-reanimated';
function ParallaxHeader() {
const scrollY = useSharedValue(0);
const scrollHandler = useAnimatedScrollHandler({
onScroll: (e) => {
scrollY.value = e.contentOffset.y;
},
});
const headerStyle = useAnimatedStyle(() => ({
transform: [{
translateY: interpolate(
scrollY.value,
[0, 300],
[0, -150],
Extrapolation.CLAMP,
),
}],
opacity: interpolate(
scrollY.value,
[0, 200],
[1, 0],
Extrapolation.CLAMP,
),
}));
return (
Parallax Header
{/* Content */}
);
}
8. Best Practices
| Praktik | Alasan |
|---|---|
| Gunakan shared values untuk data animasi | Tidak trigger re-render React |
| Minimalkan runOnJS calls | Bridge JS↔UI ada overhead |
| Gunakan Layout Animations | Kurangi kode animasi manual |
| Hindari membuat worklet baru di render | Bisa menyebabkan re-compilation |
| Gunakan gesture-handler langsung | Integrasi native lebih dalam |