Animations can significantly enhance the user experience of any mobile application. They make interactions feel more intuitive, provide feedback, and create a polished, professional look. However, achieving smooth, high-performance animations in React Native can be challenging due to the JavaScript thread’s limitations. This is where Reanimated 3 comes in. This powerful library allows developers to create complex, performant animations with ease. In this blog post, we’ll explore how to use Reanimated 3 to build high-performance animations in your React Native app using Expo.
Why Reanimated 3?
Reanimated 3 stands out from other animation libraries because it runs animations on the UI thread, not the JavaScript thread. This means animations remain smooth and responsive, even under heavy load or when the JavaScript thread is busy. Reanimated 3 also introduces a new declarative API, making it easier to create and manage animations.
Setting Up Reanimated 3
Setting up Reanimated 3 with Expo is straightforward. Follow the steps below to get started.
Step 1: Create a New Expo Project
First, we need to create a new Expo project using the Reanimated template:
yarn create expo-app my-app -e with-reanimated
cd my-app
yarn start --reset-cache
Creating Basic Animations
Let’s start with a simple animation example: changing the width of a box when a button is pressed.
Sample Animated App Code
The following code is for the App.js file created during the setup:
import Animated, {
useSharedValue,
withTiming,
useAnimatedStyle,
Easing,
} from "react-native-reanimated";
import { View, Button } from "react-native";
import React from "react";
export default function AnimatedStyleUpdateExample(props) {
const randomWidth = useSharedValue(10);
const config = {
duration: 500,
easing: Easing.bezier(0.5, 0.01, 0, 1),
};
const style = useAnimatedStyle(() => {
return {
width: withTiming(randomWidth.value, config),
};
});
return (
<View
style={{
flex: 1,
alignItems: "center",
justifyContent: "center",
flexDirection: "column",
}}
>
<Animated.View
style={[
{ width: 100, height: 80, backgroundColor: "black", margin: 30 },
style,
]}
/>
<Button
title="toggle"
onPress={() => {
randomWidth.value = Math.random() * 350;
}}
/>
</View>
);
}
🤔 Looking for a resource to power up your React Native skills? Search no more! Check out this AMAZING hands-on guide. 🔥
React and React Native: A complete hands-on guide to modern web and mobile development with React.js
🤓 Practical Tutorial: Building an Animated To-Do List 🛸
Now, let’s build a practical example – an animated to-do list app using Reanimated 3. This app will allow users to add, remove, and reorder tasks with smooth animations.
✨ TL;DR – Checkout the GitHub Repo!✨
🔗 ===> judescripts/rn-reanimated: DevToys.io blog tutorial on working with React Native Reanimated 3 (github.com)
Step 1: Set Up the Project
Create a new Expo project if you haven’t already:
yarn create expo-app my-todo-app -e with-reanimated
cd my-todo-app
Step 2: Install react-native-gesture-handler
Ensure react-native-gesture-handler is installed:
yarn add react-native-gesture-handler
Step 3: Implement the To-Do List
Create the ToDoList.js component:
import React, { useState } from 'react';
import { View, TextInput, Button, StyleSheet, FlatList } from 'react-native';
import TaskItem from './TaskItem';
const ToDoList = () => {
const [tasks, setTasks] = useState([]);
const [task, setTask] = useState('');
const addTask = () => {
if (task.trim()) {
setTasks([...tasks, { id: Date.now().toString(), title: task }]);
setTask('');
}
};
const removeTask = (id) => {
setTasks((prevTasks) => prevTasks.filter((item) => item.id !== id));
};
const renderItem = ({ item }) => (
<TaskItem item={item} removeTask={removeTask} />
);
return (
<View style={styles.container}>
<TextInput
style={styles.input}
value={task}
onChangeText={setTask}
placeholder="Add a task"
/>
<Button title="Add Task" onPress={addTask} />
<FlatList
data={tasks}
renderItem={renderItem}
keyExtractor={(item) => item.id}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
},
input: {
height: 40,
borderColor: 'gray',
borderWidth: 1,
marginBottom: 10,
paddingHorizontal: 10,
},
});
export default ToDoList;
Create the TaskItem.js component using the new Gesture Handler API:
import React from 'react';
import { Text, StyleSheet } from 'react-native';
import Animated, { useSharedValue, useAnimatedStyle, withSpring, withTiming, runOnJS } from 'react-native-reanimated';
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
const TaskItem = ({ item, removeTask }) => {
const translateX = useSharedValue(0);
const taskHeight = useSharedValue(70);
const animatedStyle = useAnimatedStyle(() => {
return {
transform: [{ translateX: translateX.value }],
height: taskHeight.value,
opacity: taskHeight.value / 70,
};
});
const panGesture = Gesture.Pan()
.onBegin(() => {
// Initialize context here if needed
})
.onUpdate((event) => {
translateX.value = event.translationX;
})
.onEnd(() => {
if (translateX.value < -150) {
translateX.value = withTiming(-200);
taskHeight.value = withTiming(0, {}, () => {
runOnJS(removeTask)(item.id);
});
} else {
translateX.value = withSpring(0);
}
});
return (
<GestureDetector gesture={panGesture}>
<Animated.View style={[styles.task, animatedStyle]}>
<Text>{item.title}</Text>
</Animated.View>
</GestureDetector>
);
};
const styles = StyleSheet.create({
task: {
height: 70,
backgroundColor: 'lightgrey',
justifyContent: 'center',
paddingHorizontal: 20,
marginBottom: 10,
borderRadius: 10,
},
});
export default TaskItem;
Update your App.js to include the ToDoList component:
import 'react-native-gesture-handler';
import 'react-native-reanimated';
import React from 'react';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import ToDoList from './ToDoList';
export default function App() {
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<ToDoList />
</GestureHandlerRootView>
);
}
Running the Project
To run the project, use the following commands based on the platform you want to test:
Start the Expo development server:
yarn start --reset-cache
This will give you options to choose the platform, or you can
Directly Start Run on iOS:
yarn ios
Directly Start Run on Android:
yarn android
🫠 Now try to add tasks and swipe to the left to delete and you’ll see some cool animations!🧙🏻♂️
Conclusion
Reanimated 3 provides a powerful and efficient way to create high-performance animations in React Native. By running animations on the UI thread and offering a declarative API, Reanimated 3 ensures smooth and responsive animations, even under heavy load. In this tutorial, we built an animated to-do list app that allows users to add, remove, and reorder tasks with smooth animations. Start experimenting with Reanimated 3 today and take your React Native app’s user experience to the next level!
Next Steps
For an additional challenge, try implementing the ability to reorder tasks within the to-do list. Share your results and any issues you encounter!
Top comments (0)