Animations in React Native with Reanimated 2: A Comprehensive Guide

Table of Contents
Big thanks to our contributors those make our blogs possible.

Our growing community of contributors bring their unique insights from around the world to power our blog. 

Smooth, high-performance animations elevate your React Native app’s user experience—making transitions feel natural, interactions more engaging, and interfaces more delightful. Reanimated 2, the next-generation animation library from Software Mansion, brings native-threaded worklets, an intuitive hooks-based API, and powerful layout/gesture integrations to React Native. In this deep-dive guide, you’ll learn:

  1. Why Reanimated 2? Key advantages over built-in APIs
  2. Installation & Setup: Getting started in your project
  3. Core Concepts: Shared values, worklets, and animated styles
  4. Basic Animations: withTiming, withSpring, and sequences
  5. Gesture-Driven Animations: Integrating with React Native Gesture Handler
  6. Layout Animations: Animate entering/exiting and layout changes
  7. Performance Tips: Best practices for 60 fps on both platforms
  8. Real-World Example: Building a draggable, springy card list
  9. Conclusion & Next Steps

By the end, you’ll have a solid foundation to craft dynamic, fluid animations entirely on the UI thread—no bridges blocking your 60 fps goal.

1. Why Reanimated 2?

Native-Threaded Animations

Unlike React Native’s Animated (which runs most logic on the JS thread), Reanimated 2 executes animation worklets on the UI thread—eliminating jank due to JS bottlenecks.

First-Class Worklets

Write animation logic in JavaScript functions annotated with "worklet"—Reanimated compiles them into small units that run natively.

Declarative Hooks API

With useSharedValue, useAnimatedStyle, and hooks like useAnimatedGestureHandler, your animation code lives alongside your React components in a clean, declarative style.

Layout & Shared Value Integration

Built-in support for layout transitions (LayoutAnimations) and easy sharing of values across components let you orchestrate complex UI flows with minimal boilerplate.

2. Installation & Setup

Prerequisites

  • React Native ≥ 0.64
  • React ≥ 17.

Install Dependencies

bashCopyEdityarn add react-native-reanimated react-native-gesture-handler

Configure Reanimated Plugin

In babel.config.js:

jsCopyEditmodule.exports = {
  presets: ['module:metro-react-native-babel-preset'],
  plugins: ['react-native-reanimated/plugin'], // must be last
};

iOS & Android

  • iOS: Run cd ios && pod install
  • Android: Ensure Java 11 compatibility and enable Hermes for best performance.

3. Core Concepts

Shared Values

Holds mutable state that can drive animations:

jsCopyEditimport { useSharedValue } from 'react-native-reanimated';

const progress = useSharedValue(0); // initial value

Worklets

Functions tagged with "worklet" that run on the UI thread:

jsCopyEditfunction double(x) {
  'worklet';
  return x * 2;
}

Animated Styles

Bind shared values to component styles:

jsCopyEditimport { useAnimatedStyle, withTiming } from 'react-native-reanimated';

const animatedStyle = useAnimatedStyle(() => ({
  opacity: withTiming(progress.value, { duration: 500 }),
}));

Apply to Animated.View:

jsxCopyEdit<Animated.View style={[styles.box, animatedStyle]} />

4. Basic Animations

Timing Animation

Smooth, configurable duration:

jsCopyEditprogress.value = withTiming(1, { duration: 1000 });

Spring Animation

Physics-based bounce:

jsCopyEditprogress.value = withSpring(1, {
  stiffness: 100,
  damping: 10,
  mass: 1,
});

Sequences & Delays

Chain or stagger:

jsCopyEditimport { withSequence, withDelay } from 'react-native-reanimated';

progress.value = withSequence(
  withTiming(1, { duration: 500 }),
  withDelay(200, withSpring(0.5))
);

5. Gesture-Driven Animations

Combine with React Native Gesture Handler for interactive UI:

jsxCopyEditimport { PanGestureHandler } from 'react-native-gesture-handler';
import { useAnimatedGestureHandler, useAnimatedStyle } from 'react-native-reanimated';

function DraggableBox() {
  const translateX = useSharedValue(0);
  const translateY = useSharedValue(0);

  const gestureHandler = useAnimatedGestureHandler({
    onStart: (_, ctx) => {
      ctx.startX = translateX.value;
      ctx.startY = translateY.value;
    },
    onActive: (event, ctx) => {
      translateX.value = ctx.startX + event.translationX;
      translateY.value = ctx.startY + event.translationY;
    },
    onEnd: () => {
      translateX.value = withSpring(0);
      translateY.value = withSpring(0);
    },
  });

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

  return (
    <PanGestureHandler onGestureEvent={gestureHandler}>
      <Animated.View style={[styles.box, style]} />
    </PanGestureHandler>
  );
}

6. Layout Animations

Animate component mount/unmount or layout changes:

jsxCopyEditimport { Layout, FadeIn, FadeOut } from 'react-native-reanimated';

function Item({ visible }) {
  return visible ? (
    <Animated.View
      entering={FadeIn.duration(300)}
      exiting={FadeOut.duration(200)}
      layout={Layout.springify()}>
      <Text>🎉 New Item!</Text>
    </Animated.View>
  ) : null;
}

Use Animated.FlatList for lists with dynamic items to auto-animate reordering.

7. Performance Tips

  • Keep Worklets Lean: Avoid heavy computations; delegate to shared values and native libraries where possible.
  • Batch Updates: Group multiple value changes inside a single frame for smoother animations.
  • Use useAnimatedReaction to coordinate between shared values without re-rendering JS.
  • Enable Hermes and ProGuard/R8 on Android to shrink and optimize your JS bundle.

8. Real-World Example: Springy Card List

A scrollable list where tapping a card expands it with a spring effect:

jsxCopyEditfunction Card({ data }) {
  const expanded = useSharedValue(false);

  const animatedStyle = useAnimatedStyle(() => ({
    height: withSpring(expanded.value ? 200 : 100),
    margin: withSpring(expanded.value ? 16 : 8),
  }));

  return (
    <TapGestureHandler onEnded={() => (expanded.value = !expanded.value)}>
      <Animated.View style={[styles.card, animatedStyle]}>
        <Text>{data.title}</Text>
      </Animated.View>
    </TapGestureHandler>
  );
}

Wrap in Animated.FlatList for a performant scrolling container.

Conclusion

Reanimated 2 unlocks the power of native-threaded, hook-based animations in React Native—enabling 60 fps interactions, fluid gestures, and sophisticated layout transitions. By mastering shared values, worklets, gesture handlers, and layout animations, you’ll deliver polished, performant experiences that delight users. Start experimenting with the examples above, explore the rich plugin ecosystem (e.g., reanimated bottom sheets, shared-element transitions), and push the boundaries of what’s possible in mobile UI.

Let's connect on TikTok

Join our newsletter to stay updated

Sydney Based Software Solutions Professional who is crafting exceptional systems and applications to solve a diverse range of problems for the past 10 years.

Share the Post

Related Posts