iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Animations

React Native ships Animated + the modern Reanimated library for 60fps animations driven on the native UI thread. Use Reanimated 3+ — declarative, hooks-based, and far smoother than the legacy bridge.

Reanimated 3: spring, gesture, layout

EXAMPLE
// npm i react-native-reanimated react-native-gesture-handler
import Animated, {
    useSharedValue,
    useAnimatedStyle,
    withSpring,
    withTiming,
    withRepeat,
    withSequence,
    interpolate,
    Extrapolate,
    runOnJS,
    Layout,
    FadeIn,
    FadeOut,
} from 'react-native-reanimated';
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
import { View, StyleSheet, Text } from 'react-native';
import { useEffect } from 'react';

// 1) Basic — translate on mount
export function Slide() {
    const x = useSharedValue(-100);
    useEffect(() => { x.value = withSpring(0); }, []);
    const style = useAnimatedStyle(() => ({
        transform: [{ translateX: x.value }],
    }));
    return <Animated.View style={[styles.box, style]} />;
}

// 2) On press — sequence
export function PressMe() {
    const scale = useSharedValue(1);
    const onPress = () => {
        scale.value = withSequence(
            withTiming(1.2, { duration: 80 }),
            withSpring(1),
        );
    };
    const style = useAnimatedStyle(() => ({ transform: [{ scale: scale.value }] }));
    return (
        <Animated.View style={[styles.btn, style]} onTouchEnd={onPress}>
            <Text>Tap</Text>
        </Animated.View>
    );
}

// 3) Drag with Gesture Handler
export function Draggable() {
    const tx = useSharedValue(0);
    const ty = useSharedValue(0);
    const offsetX = useSharedValue(0);
    const offsetY = useSharedValue(0);

    const pan = Gesture.Pan()
        .onUpdate((e) => {
            tx.value = offsetX.value + e.translationX;
            ty.value = offsetY.value + e.translationY;
        })
        .onEnd(() => {
            offsetX.value = tx.value;
            offsetY.value = ty.value;
        });

    const style = useAnimatedStyle(() => ({
        transform: [{ translateX: tx.value }, { translateY: ty.value }],
    }));

    return (
        <GestureDetector gesture={pan}>
            <Animated.View style={[styles.box, style]} />
        </GestureDetector>
    );
}

// 4) Interpolate — derive multiple styles from one shared value
export function ScrollHeader({ scrollY }) {
    const style = useAnimatedStyle(() => {
        const opacity = interpolate(scrollY.value, [0, 80], [1, 0], Extrapolate.CLAMP);
        const height  = interpolate(scrollY.value, [0, 80], [120, 56], Extrapolate.CLAMP);
        return { opacity, height };
    });
    return <Animated.View style={[styles.header, style]} />;
}

// 5) Layout animations — list reflow for free
export function List({ items }) {
    return items.map((it) => (
        <Animated.View
            key={it.id}
            layout={Layout.springify()}
            entering={FadeIn.duration(150)}
            exiting={FadeOut.duration(150)}
        >
            <Text>{it.label}</Text>
        </Animated.View>
    ));
}

// 6) Loops + repeat
const rot = useSharedValue(0);
useEffect(() => {
    rot.value = withRepeat(withTiming(360, { duration: 1500 }), -1, false);
}, []);

// 7) Call JS from a worklet — runOnJS
const onLongDrag = (px) => Alert.alert(`dragged ${px}px`);
const pan = Gesture.Pan().onEnd((e) => {
    if (Math.abs(e.translationX) > 150) runOnJS(onLongDrag)(e.translationX);
});

// 8) Tips
//   • Use shared values, not React state, for animated values — avoids re-renders
//   • Worklets run on the UI thread — must not touch React state directly (use runOnJS)
//   • Use Layout + entering/exiting for declarative list animations
//   • Animations run at native FPS — even during heavy JS work

const styles = StyleSheet.create({
    box: { width: 80, height: 80, backgroundColor: 'crimson', borderRadius: 16 },
    btn: { padding: 12, backgroundColor: '#eef', borderRadius: 8 },
    header: { backgroundColor: '#111' },
});

Why it matters

Reanimated 3 worklets run on the UI thread, so animations don’t skip when the JS thread is busy. Pair with Gesture Handler for drag/swipe interactions that feel native — the legacy Animated + PanResponder combo is no contest.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
import Animated, { useSharedValue, useAnimatedStyle, withSpring } from 'react-native-reanimated';
const x = useSharedValue(0);
const style = useAnimatedStyle(() => ({ transform: [{ translateX: x.value }] }));
return <Animated.View style={[box, style]} onTouchEnd={() => x.value = withSpring(100)} />;
Try it Yourself »

Discussion

Loading…