![]()
Open the Tiktok or Facebook app on your phone and try swiping and tapping. You will see that things do not appear and disappear abruptly. Buttons bounce when touched, images fade in, and lists slide perfectly along with your finger.
That is the power of Animation. It gives a "soul" to the application, making users feel that the app responds faster and smoother than it actually does.
In React Native, there are many ways to do Animation, but today we will skip the old methods to learn the ultimate and most powerful tool available today: React Native Reanimated 3.
1. The pain of traditional animation (Animated API)
React Native has a built-in tool called Animated. However, if you use it for complex effects, your application is very prone to lag (frame drops). Why is that?

To understand this, you need to know the core architecture of a phone:
- JS Thread: Where your JavaScript code lives. It takes care of calling APIs, calculating logic, and managing State.
- UI Thread: Where colors and images are directly drawn onto the phone screen.
With the old approach, every time a frame changes (for example, a button gets 1 pixel larger), the JS Thread has to calculate and then send a "command" to the UI Thread to draw. It has to send this back and forth 60 times in 1 second (60fps). If the JS Thread is busy calculating a large chunk of data from an API at that time, the command sending will be congested ➔ The animation gets stuck!
Reanimated 3 was born to solve this problem. It allows you to send the entire "animation script" straight to the UI Thread. The UI Thread will automatically execute smoothly at 60-120fps without needing to ask the JS Thread anymore, regardless of whether the JS Thread is hanging or not!
2. Installing Reanimated 3 in Expo
With Expo, installing this library is extremely simple. Open the Terminal and run the command:
npx expo install react-native-reanimated

⚠️ MANDATORY STEP: After installing, you must open the babel.config.js file in the root directory of the project and add the Reanimated plugin at the very end. Your file will look something like this:
module.exports = function (api) {
api.cache(true)
return {
presets: ['babel-preset-expo'],
plugins: [
'react-native-reanimated/plugin', // MUST BE AT THE VERY END!
],
}
}
After that, restart the server with the command npx expo start -c (add -c to clear the cache).
3. The most powerful tools of Reanimated 3
To create any movement, you only need to remember exactly these 3 sets of tools (Hooks):
Concept 1: useSharedValue
(The invisible state variable)
Similar to useState, but useSharedValue is specifically designed to store numbers (like opacity, size, coordinates) without causing the screen to re-render every time the value changes. This data is shared directly with the UI Thread.
Concept 2: useAnimatedStyle
(The connecting wire)
The useSharedValue variable is just a lifeless number. You need to use useAnimatedStyle to tell the View tag: "Hey View tag, let's take this number as your width!".
Concept 3: withTiming, withSpring
(The animation functions)
Instead of abruptly changing the value from 1 to 100, these functions help the number run from 1 to 100 gradually, creating a motion effect.
withTiming: Moves steadily over time (like CSS Transition).withSpring: Bouncing motion like a spring (Very popular in Mobile UI).
4. Practice: Super smooth "spring bounce" button
Let's create a very lively "Confirm" button. When the user presses it, the button will sink down a bit, and when they release it, it will bounce back up like a spring.
import React from 'react'
import { View, Text, Pressable, StyleSheet } from 'react-native'
// 1. Import tools from the reanimated library (Note: Must have the word Animated)
import Animated, { useSharedValue, useAnimatedStyle, withSpring } from 'react-native-reanimated'
export default function BounceButton() {
// 2. Initialize default value for Scale. 1 means 100% of original size.
const scale = useSharedValue(1)
// 3. Connect the scale value to the transform property of CSS
const animatedStyle = useAnimatedStyle(() => {
return {
transform: [{ scale: scale.value }],
}
})
// 4. Handle when starting to press the finger in
const handlePressIn = () => {
// Shrink to 90% (0.9) with spring effect
scale.value = withSpring(0.9)
}
// 5. Handle when lifting the finger out
const handlePressOut = () => {
// Bounce back to 100% (1) original size
scale.value = withSpring(1)
}
return (
<View style={styles.container}>
{/* 6. MANDATORY: Use Animated.View tag instead of normal View */}
<Animated.View style={[styles.buttonWrapper, animatedStyle]}>
{/* Use Pressable to catch In/Out events most accurately */}
<Pressable onPressIn={handlePressIn} onPressOut={handlePressOut} style={styles.button}>
<Text style={styles.text}>Press Me!</Text>
</Pressable>
</Animated.View>
</View>
)
}
const styles = StyleSheet.create({
container: { flex: 1, justifyContent: 'center', alignItems: 'center' },
buttonWrapper: {
// The outer wrapper will be responsible for the animation
},
button: {
backgroundColor: '#0984e3',
paddingVertical: 15,
paddingHorizontal: 40,
borderRadius: 30,
elevation: 5, // Android shadow
shadowColor: '#000', // iOS shadow
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.3,
},
text: { color: 'white', fontSize: 18, fontWeight: 'bold' },
})
With just a few short lines of code, you have created an extremely satisfying physical interaction without putting any burden on the processor!
5. Automatic appearance effect (Entering Animation)
Sometimes, you want a list of elements to automatically fade in and slide up from the bottom when the screen just opens (like flipping cards). Reanimated 3 provides a built-in set of Layout Animations, helping you do this with just 1 line of code!

import Animated, { FadeInUp } from 'react-native-reanimated'
export default function CardItem() {
return (
// Use the entering property and pass the FadeInUp effect into it
// Add duration to slow down the time a bit
<Animated.View entering={FadeInUp.duration(500).springify()} style={styles.card}>
<Text>Card Content</Text>
</Animated.View>
)
}
No need for complex useSharedValue calculations, Reanimated will automatically take care of all the math in the background when the component is rendered onto the screen.
Conclusion: Goodbye lag, hello smoothness
Using Reanimated 3 is the hallmark of a Senior React Native developer:
- Always use
Animated.View,Animated.Textto wrap elements you want to animate. - Use
useSharedValueto store parameters instead ofuseState. - Use
useAnimatedStyleto turn parameters into actual styles. - Utilize
withSpringto create a natural, realistic feel for users.
In this article, we have only touched the surface of automatic effects. How can users touch the screen, swipe, and drag a View around (like the Tinder dating app)?
Stay tuned for more useful knowledge in the upcoming articles!