Unleashing Motion Magic with React Native Reanimated
React Native Reanimated is a powerful library that reimagines animation capabilities in React Native applications. It provides a more comprehensive, low-level abstraction for the Animated library API, allowing developers to create fluid, high-performance animations and gesture-driven interfaces. With Reanimated, you can bring your mobile apps to life with smooth transitions, interactive elements, and complex UI behaviors that were previously challenging to implement.
Key Features of React Native Reanimated
React Native Reanimated offers a rich set of features that set it apart from traditional animation libraries:
- Native Driver: Utilizes native-driven animations for optimal performance.
- Worklets: Allows running JavaScript on the UI thread for smoother animations.
- Gesture Handling: Seamlessly integrates with gesture libraries for interactive animations.
- Shared Values: Provides a way to share values between the JavaScript thread and the UI thread.
- Layout Animations: Enables easy creation of layout transitions and animations.
Getting Started with Reanimated
To begin your journey with React Native Reanimated, you’ll first need to install the library in your project. Open your terminal and run:
npm install react-native-reanimated
For yarn users:
yarn add react-native-reanimated
After installation, you’ll need to configure your project to use Reanimated. This process may vary depending on your React Native version and whether you’re using Expo or bare React Native.
Basic Usage: Creating Your First Animation
Let’s start with a simple example to demonstrate the power of Reanimated. We’ll create a box that fades in when the component mounts.
import React from 'react';
import { View } from 'react-native';
import Animated, { useSharedValue, useAnimatedStyle, withTiming } from 'react-native-reanimated';
const FadingBox = () => {
const opacity = useSharedValue(0);
const animatedStyle = useAnimatedStyle(() => {
return {
opacity: opacity.value,
};
});
React.useEffect(() => {
opacity.value = withTiming(1, { duration: 1000 });
}, []);
return (
<Animated.View
style={[
{ width: 100, height: 100, backgroundColor: 'blue' },
animatedStyle,
]}
/>
);
};
In this example, we use useSharedValue
to create a mutable value that can be shared between the JavaScript thread and the UI thread. The useAnimatedStyle
hook creates a style object that depends on this shared value. Finally, withTiming
is used to animate the opacity from 0 to 1 over a duration of 1000 milliseconds.
Advanced Usage: Gesture-Driven Animations
One of Reanimated’s strengths is its ability to create smooth, gesture-driven animations. Let’s create a draggable box that springs back to its original position when released.
import React from 'react';
import { View, StyleSheet } from 'react-native';
import Animated, {
useSharedValue,
useAnimatedStyle,
useAnimatedGestureHandler,
withSpring,
} from 'react-native-reanimated';
import { PanGestureHandler } from 'react-native-gesture-handler';
const DraggableBox = () => {
const translateX = useSharedValue(0);
const translateY = useSharedValue(0);
const panGestureHandler = 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 animatedStyle = useAnimatedStyle(() => {
return {
transform: [
{ translateX: translateX.value },
{ translateY: translateY.value },
],
};
});
return (
<PanGestureHandler onGestureEvent={panGestureHandler}>
<Animated.View style={[styles.box, animatedStyle]} />
</PanGestureHandler>
);
};
const styles = StyleSheet.create({
box: {
width: 100,
height: 100,
backgroundColor: 'blue',
},
});
This example demonstrates how to use useAnimatedGestureHandler
to create a gesture handler that updates shared values based on the user’s touch input. The withSpring
function is used to create a spring animation that returns the box to its original position when the gesture ends.
Worklets: Running JavaScript on the UI Thread
Worklets are a unique feature of Reanimated that allow you to run JavaScript code on the UI thread, ensuring smooth animations even when the JavaScript thread is busy. Here’s an example of how to use a worklet to create a custom animation:
import Animated, {
useSharedValue,
useAnimatedStyle,
withRepeat,
withTiming,
Easing,
runOnUI,
} from 'react-native-reanimated';
const PulsingCircle = () => {
const scale = useSharedValue(1);
const pulseWorklet = runOnUI((amplitude: number, duration: number) => {
'worklet';
scale.value = withRepeat(
withTiming(amplitude, { duration, easing: Easing.inOut(Easing.ease) }),
-1,
true
);
});
React.useEffect(() => {
pulseWorklet(1.2, 1000);
}, []);
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ scale: scale.value }],
}));
return <Animated.View style={[styles.circle, animatedStyle]} />;
};
In this example, we define a worklet using runOnUI
that creates a pulsing animation. The worklet is executed on the UI thread, ensuring smooth performance even if the JavaScript thread becomes blocked.
Layout Animations: Smooth Transitions
Reanimated also provides powerful tools for creating layout animations. Here’s an example of how to use Layout.springify()
to create smooth transitions when elements are added or removed from a list:
import Animated, { Layout } from 'react-native-reanimated';
const AnimatedList = ({ items }) => {
return (
<Animated.FlatList
data={items}
renderItem={({ item }) => (
<Animated.View
layout={Layout.springify()}
style={styles.listItem}
>
<Text>{item}</Text>
</Animated.View>
)}
keyExtractor={(item) => item}
/>
);
};
This code creates a list where items smoothly animate into place when added or removed, using a spring animation for a natural feel.
Conclusion
React Native Reanimated opens up a world of possibilities for creating fluid, high-performance animations in your mobile applications. From simple fades to complex gesture-driven interfaces, Reanimated provides the tools you need to bring your UI to life. By leveraging features like worklets, shared values, and native drivers, you can create animations that run smoothly even on less powerful devices.
As you continue to explore Reanimated, you’ll discover even more advanced techniques and optimizations. For further reading, check out our articles on React Native Gesture Handler and React Native Skia to learn how to combine these libraries for even more powerful UI interactions.
Remember, great animations are about enhancing user experience, not just adding visual flair. Use Reanimated thoughtfully to guide users through your app, provide feedback, and create delightful interactions that keep them coming back for more.