The Basics of React Native Animations

Everything moves. Animation is this science of what is a good movement and what isn’t. Whether it is with objects or drawings, animation takes anything from one state to another in the smoothest way possible.

In this series, I will help you to understand how to bring the art of animation into React Native. In today’s first chapter, let’s start with the basics.

This was first published as a video for the How To Animated series. If you learn better through audio/image, I highly recommend it.

The problem

Let’s think of a square. If I want it to move, I can change its horizontal position to the left or the right.

Now, if I want to do this with React, that’s quite simple: I create a component, which renders that square, and using a state property I can play with its position:

import React, { useState } from 'react';
import { View } from 'react-native';
export default () => {
const [translation, setTranslation] = useState(0);

return (
<View
style={{
width: 100,
height: 100,
backgroundColor: 'orange',
transform: [{ translateX: translation }],
}}
/>
);
};

Here, if translation equals zero, then we’re at the initial position. If I increase its value, the square will move to the right.

const [translation, setTranslation] = useState(50);

Likewise, if I decrease “translation” to some value lower than zero, the square will go to the left.

const [translation, setTranslation] = useState(-50);

Great. Now, let’s go back to our initial position and whenever the square is rendered, we want to update the “transition” state value:

const [translation, setTranslation] = useState(0);useEffect(() => {
setTranslation(50);
}, []);

Because I set the value to 50 straight away, the square won’t animate! What we could do in this case, is to increase translation by 1 every 25 milliseconds:

useEffect(() => {
for (let i = 0; i < 50; i++) {
setTimeout(() => {
setTranslation(i);
}, 25 * i);
}

}, []);

Now it animates but there are two issues with this method:

  • State updates are asynchronous. This means in our case that these updates might not come at the time we think they will.
  • This animation will be handled by the Javascript thread which is the main thread for your application. If it is already busy fetching data or doing something else, your animation might get stuck in the middle.

Knowing there is a better way of animating should be no surprise to you since this is the whole point of this series so let’s look at how we can get this square to smoothly animate to the right.

Animated, the solution

React Native comes with an animation library called Animated which solves our performance issues.

The best part of Animated is that it can run animations on the UI thread which is a separate one from the JavaScript thread. This allows our animations to run much smoother.

To use Animated, just import it from React Native, so we can get started:

import { Animated, View } from 'react-native';

Our first change is to replace useState with an Animated value:

const translation = new Animated.Value(0);

Since this value is an instance of a class, we will wrap it in a useRef call so that it only gets created once, when the component renders for the first time:

const translation = useRef(new Animated.Valu(0)).current;

Also, because translation is not a regular state property anymore, and thus returns something different than just a number, we need to change our View so that it knows how to deal with an animated value in its styling. To do so, just replace View with an Animated.View:

<Animated.View

As a side note, you can find other built-in animated components such as Animated.Image, Animated.Text

Also, since we don’t have a state setter function anymore, we can replace setTranslation with translation.setValue which works the same way but for animated values:

useEffect(() => {
for (let i = 0; i < 50; i++) {
setTimeout(() => {
translation.setValue(i);
, 25 * i);
}
}, []);

At this point, using Animated we managed to get the same result so you might be wondering, where’s the magic speed I promised? Well, there is actually one more step.

Native animations

(Kevin knows)

If you look at the code, you can see that what all we are animating is this square’s translation from 0 to 50 pixels to the right.

Now, setting its value manually every 25ms isn’t the best way of animating things. Luckily, Animated comes with helper functions that directly send a command to the UI thread.

Again, all we want is to change the translation value over time from 0 to 50. With Animated, you can do this in an optimized way using Animated.timing:

useEffect(() => {
Animated.timing(translation, {
toValue: 50,
}).start();

}, []);

This will take the animated value translation and change its value to 50. Calling start on this animation…starts the animation.

One last detail here is that Animated is built in a way so that you can improve the performance even more, by using what they called a native driven animation.

This makes your animations run on the UI thread directly and all you need to make your animation compatible is to add the useNativeDriver property to your configuration:

Animated.timing(translation, {
toValue: 50,
useNativeDriver: true,
}).start();

That’s pretty simple, isn’t it? Okay, now that you know the basics of Animated, let’s wrap this up.

Recap

If there are two things to remember today, here they are:

  • Animating using state properties isn’t the way to animate in React Native for 2 reasons: it isn’t optimized for it in any way and the animation will run on the same thread as all your app logic runs on (which can slow it down when your app is busy).
  • Instead, you can use the Animated library which allows animating elements in a much more optimized way. To do so, you have to: start with Animated.Value to represent animated values, animate them over time using Animated.timing and add useNativeDriver to run them on the UI thread.

Alright, that’s it for now. In the next chapter, we will look at more types of animations using what we’ve learned today.

New chapters will be released on a weekly-basis. Remember to follow me if you don’t want to miss any.

Also published in this series:

I often find myself reading too many articles on the internet

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store