To provide users with smoothly working apps, we want our animations to run at 60 fps or even better. However it may sound like a bit of a challenge, with an Open Source library called react-native-reanimated, we can do it!

In this article, I’ll describe to you what React Native Reanimated is and how it works under the hood basing on three use cases.

What is React Native Reanimated?

React Native Reanimated is an Open Source library used in React Native mobile development to create smooth animations and interactions that run on the UI thread. The library allows developers to declare animations on the JavaScript thread and run them on the native one to achieve smooth animations regardless of whether the JS thread is busy or not.

Despite being really powerful, the library has a very steep learning curve. First of all, we have to learn a specific language in order to build animations.

Second of all, we have to change our mindset and start thinking declaratively instead of imperatively.

It can be difficult to wrap your head around this style of building animations at first. That’s why I will dive deeply under the hood of this library what, hopefully, will help you understand how it works and what idea stands behind it.

The idea behind Animated components

At first, I want you to understand what the purpose of rendering <Animated.View/> is and why we can use Animated.Node values in the style prop.

The example code snippet below uses Animated.Node to set the opacity (it is an instance of the Animated.Node) style property of the Animated.View.

Let’s go through it, step by step.

At the beginning of our component, we are creating Animated.Value node with an initial value equal to 1 that represents opacity.

At first, we render Animated.View and we start building our animation tree on both JS and native sides at the same time. To avoid flickering, before sending our nodes, we calculate initial values on the JS side and library by using setNativeProps method to set these values directly as component props. The way how we calculate values on both JS and the native side is very similar.

In the diagram below, we have our animation tree that is replicated on both sides (native and JS).

Note: All diagrams below represent animated nodes not props in React!

react native animated library diagram 1

As you may already observe, nodes have a bidirectional connection. It means that the node can be accessed by going deeper into the tree (from parent) or by going upwards to the parent (from children). This technique is crucial for the animation tree evaluation process that will be described below.

The building tree process uses the bottom to top approach. It means that: Props node wants to be attached to the tree but it requires its children to be attached before. Value node will become the eldest ancestor (in our case it is the root of our animation tree). It’s children’s will to inform that they should be evaluated in the next loop tick.

react native animated library diagram 2

Then, all marked nodes and their children will be processed in the next loop tick. In this step, we want to find all affected final nodes by searching through marked children nodes. Final nodes are one of these types: Props or Always (we will cover it later on). Nodes are evaluated recursively from the top to bottom (starting from the final nodes). That’s why this bidirectional connection is crucial in order to make this process work correctly.

In our case, the Props node will evaluate Style node and Style node will evaluate Value node. The Value node will return actual held value that will be used by its parent and so on.

react native animated diagram 3

After all the updates, the library is taking care of UI updates on the native side therefore new values will be visible for the end users.

What about a more interactive/real-world example?

How to trigger animations?

To make an animation run, we have to trigger it, it’s quite obvious. In this chapter, I will describe two way sof triggering animations in React Native Reanimated library – by using setValue and by running Clock.

Animation triggered by setValue

We’re going to start from the ground up. Together we’ll deeply analyze a popular fade out animation that should be triggered once the button Hide has been pressed.

The only change from the previous example is that once we have pressed the Hide button then our Animated.View immediately disappears. What happened here? Look at the diagram below.

react native animated 4 diagram
react native animated diagram 3

Value node informs that its value has been updated. As a result of that, all its children should be re-evaluated. Node manager will find our Props final node and start re-evaluation from there. In the end, re-evaluated Props node will be used for the UI updates.

Okay, but there was no animation at all right? Currently, we only know one way for triggering updates. It is done by calling setValue method directly on the Animated.Value.

Triggering animation by running Clock

We have to update our example a bit in order to make an actual animation.

There are few things that need in-depth explanation so let’s go through it step by step:

  • We create a counter variable that is used only for resetting animation state (triggering re-render)
  • We create a startAnimation that is an instance of Animated.Value .It will be used to trigger an animation once Hide button has been pressed.
  • We create an opacity as in the previous example.
  • We create a clock variables that is an instance of Animated.Clock.
  • We create state object that holds animation’s state.
  • We create config object that holds animation’s config.
  • We use useCode hook in order to define our animation tree and attach it properly. Under the hood returned value is wrapped up with Always node(second kind of final node).

Let’s look at the diagram below to see what’s going on here.

react native animated diagram 5

This is our simplified animation tree (timing isn’t a node itself it just groups up more nodes like Set Cond etc.). It also links our previous animation tree therefore updating Value (later on) will cause Props to trigger re-evaluation as well.

Once Hide button has been pressed. we set startAnimation value to 1. This node will notify node manager that it should be updated in the next loop tick . The node manager will go through children until it finds Always node (final node) which will start re-evaluation of the whole subtree.

Finding final nodes phase:

react native animated diagram 6

Evaluating Always node phase:

  • Cond node will be evaluated to true
  • StartClock will be evaluated and it will start Clock node which will notify nodes manager that it should be taken into consideration in each loop tick until it will be stopped by StopClock node.
  • Our invented Timing node will update Value node and this node will be processed in the next loop tick.
react native animated library diagram 7

Nodes that notified nodes manager are marked with red color. The final nodes found, which are Always and Props, are marked in yellow.

react native animated diagram 08

After that, the process is repeated and new values of Value node are calculated by Timing in each animation loop tick and update Value node itself. On each frame Clock, while it is running, it will notify nodes manager and as a result again Always and Props nodes will be found and then evaluated.

Summary

As you can see, the new language may seem unintuitive but offers many possibilities. To create smooth animation with this language, we need to change our mindset – from imperative to declarative and get used to Clock, which is essential for triggering animations in desired scenarios and under the assumed conditions.

If you’d like to read more about the React Native Reanimated v1 library, check out the official docs.

And that’s all for today. As the v2 is already live, stay tuned for more articles about React Native Reanimated library!