React Native: why are animations important?
Animations are important in order to create an optimal user experience, especially in the mobile world. App users have been exposed to a lot of them already, and have become familiar with their usability and beauty. And since they have hands-on experience with them, they expect them as a given in every single app they download. As per the React Native animations documentation:
Objects in motion have momentum.
Animations allow you to convey physically believable motion in your interface.

Animation systems in React Native
React Native provides two complementary animation systems: Animated and LayoutAnimation. These are 2 different APIs with a different usability and purpose.
My personal feeling is that Animated is more widely used from developers, probably because it provides more control — and it also comes with better documentation.
In this article I assume that you are familiar with Animated API and I will blog on how to achieve the best performance out of it, alongside some other practical tips.
Animated API tips: Performance and more
In order to create an animation you can find very good documentation and “how to start” examples in React Native animations documentation.
How to achieve great performance
To achieve great performance you always need to make use of the configuration prop useNativeDriver
(with value set to true
). For example, in order to animate the rotation of an image our timing function would look like that:
Animated.timing(
this.state.spinValue,
{
toValue: 1,
duration: 3000,
easing: Easing.linear,
useNativeDriver: true
}
).start();
This config prop is very very important because that way, RN sends the animation to be executed at the native realm directly passing through the bridge only once, thus achieving the best possible performance. If you are not familiar with the JavaScript/native realms and their bridge, you can get more insights in this post by @TalKol.
Now, according to RN documentation useNativeDriver
prop cannot be used for all animation types:
Not everything you can do with Animated is currently supported in Native Animated. The main limitation is that you can only animate non-layout properties, things like transform and opacity will work but flexbox and position properties won’t.
There is a way though to overcome this, if you are composing animations. For instance let’s take an example from the Math Warriors Android app where we change the size of our logo image when the user clicks the start game button.



What we do at this point is that we change the width and height of the logo simultaneously and these properties do not support use of the animated driver property. Their parallel execution though does support it as shown below:
Animated.parallel(
[
Animated.timing(
this.state.rankImageWidth,
{
toValue: 110
}
),
Animated.timing(
this.state.rankImageHeight,
{
toValue: 110
}
)
],
{
useNativeDriver: true
}
).start();
How to perform animations in loops
RN does not support loop animations out of the box, so we had to find a way. A 2nd example from Math Warriors game, which is actually the extension of our previous example, is the following: as soon as the user presses the start game button, the logo increases its size and also starts moving up and down in a loop and until the app matches the player with an opponent.



We performed this by creating a JavaScript interval id. The catch here is that in order to avoid app glitches and waiting time, you need to execute the actual animation twice: the 1st one and all the others that will follow inside a loop (JavaScript interval).
// Animation function that moves an element over y axis over time
const upAndDown = (yPositionPropName, duration, yHighPosition, yLowPosition) => {
Animated.sequence([
Animated.timing(yPositionPropName, {
duration: duration || 1000,
toValue: yHighPosition
}),
Animated.timing(yPositionPropName, {
duration: duration || 1000,
toValue: yLowPosition
})
]).start();
};
// Call and use the function above
// Start up & down animation for the first time before the loop takes over
upAndDown(
this.state.rankImageTopPosition,
this.rankImageMoveDuration,
this.rankImageHighposition,
this.rankImageLowposition
);// Loop rank image up & down movement. Total interval time
// is (animation duration x 2) time for the whole up & down move
this.rankAnimationIntervalId = setInterval(() => {
upAndDown(
this.state.rankImageTopPosition,
this.rankImageMoveDuration,
this.rankImageHighposition,
this.rankImageLowposition
);
}, this.rankImageMoveDuration * 2);// Clear the interval id after we match our player with an opponent
clearInterval(this.rankAnimationIntervalId);
How to use animatable components with styled components
For the users of styled components you can convert any of the 4 animatable components (View
, Text
, Image
, ScrollView)
to a styled component like that:
const AnimatedImage = styled(Animated.Image)`
.
.
.
`;
Validate animation’s real performance
In order to understand how your animation will behave you need to test it on a real device. Emulators cannot provide this kind of feedback. On the contrary, your animation may run flawlessly in an emulator environment and be sticky on a real device. Only the real device test can reveal if the animation shows at 60 FPS or less, which is when we experience slow breaking animations.