Reanimated 2 - the new approach to creating animations in React Native
Reanimated 2 - the new approach to creating animations in React Native
Reanimated 2 - exploring the new API to creating animations in React Native. Find out the new hooks, build custom useSlider hook, and get an understanding of animation techniques in this step by step guide.
Recently, I’ve got a chance to work with Reanimated 2 library. The new version is completely different than v1 as it exposes React hook based API. This guide uses 2.5.0 version and has been recently updated. We promise to keep updating each time a new version is released.
I have to admit, that working with the new API was quite a pleasure, firstly the new hooks set is really intuitive for React developers, secondly, animations are smooth and performant. I encourage you to start using Reanimated 2 in your React Native projects.
In this article, we are not going to focus so much on theory. If you are looking for that kind of knowledge, I refer you to the great documentation. Our aim is to take a look at Reanimated 2 hooks and learn how to use them in code. We are going to build practical examples of animated sliders using the new Reanimated 2 API and our custom useSlider hook.
You don’t need to be familiar with the previous version to make animations with Reanimated 2!
Below you can see a preview of what we will build together, step by step.
At the end of each step, there’s a link to the current code (in case you’ve got stuck). Let’s start then!
Project Setup
There is a starter repo on Github for this tutorial. We start by cloning the repo
progress - absolute positioned View, for displaying slider progress
knob - draggable element
Our first task is to animate Slider1 using Reanimated 2 hooks. Then we will build custom hook useSlider with reusable logic.
Let’s start our project
yarn ios
// or
yarn android
And move to Slider1.js file
useSharedValue
Probably you are familiar with Animated.Value concept. When it comes to Reanimated 2 we use the useSharedValue hook to keep animation ‘state’. Shared means that the value is accessible across 2 threads: UI and JS Thread.
In our example we keep two values in ‘state’:
translateX - a distance from beginning to the end of the slider.
isSliding - a boolean which tells us whether we are currently sliding or not.
Our animations are based on changing shared values. What’s important to mention, to change shared values we use .value syntax:
For instance:
isSliding.value = true
// or
translateX.value = 100
useAnimatedGestureHandler
Reanimated 2 provides us with a hook useAnimatedGestureHandler to deal with Gesture Handlers easily. The hook accepts an object where we can configure events like:
The next and one of the most important hook is useAnimatedStyle one. Inside this hook, we define style properties we want to be animated. Then we need to pass whatever hook has returned to an Animated component as a style property.
In our case, we created two animated styles.
scrollTranslationStyle - to show the Knob translation
progressStyle - to animate progress bar when the knob is being dragged
There is a problem with our slider. We can move the knob beyond our slider. Let’s fix that by adding the clamp function, that would not allow the knob to leave defined bounds.
Indeed, there is no need to define a clamp function inside the useAnimatedGestureHandler. For cleanliness, we move function definition to a separate file utils.js. Also, don’t forget to import it in our Slider1.js file.
Perhaps you have noticed that the new string appeared - "worklet". There is no need to write "worklet" directive inside reanimated 2 hooks. Each of reanimated 2 hooks, uses worklet directive under the hood.
If we want to run Javascript functions on the UI thread, we need to place "worklet" directive on the top of a function definition. (similar to our clamp method)
useDerivedValue - we use this hook, to calculate a new value, based on changing shared value. In our example we will calculate step and then return its value as a string, to animate it in AnimatedText component.
useAnimatedProp - is similar to useAnimatedStyle. The difference is that we use useAnimatedProp when we want to animate properties, which are not style properties (background, opacity, etc.)
You can find the code for slider with animated text here.
Adding onDragComplete handler and runOnJS method
Often, we want to add some feedback when the knob is being dragged to the end of the slider. With Reanimated 2 it’s quite simple to implement. Let’s assume that dragging is completed just after we have dropped the knob, and the distance from the knob to the max bound is less than 3 pt.
We call the onDragSuccess function on the UI thread when we’ve finished dragging the knob. In that case, we need to wrap our function with the runOnJS method. If we forget about wrapping our Javascript callback, Reanimated 2 will inform us about that fact by displaying an appropriate error. You can read more about runOnJS here.
So far, we have built a slider animation using Reanimated 2 hooks. As the React world loves hooks, we will move a step forward and create custom hook - useSlider. We will use this useSlider hook to animate our second slider. That would be a good test for how our shared values behave when we passed them across components.
Let’s create a new file for our hook useSlider.js. We will take our animation logic from Slider1. To increase the reusability, we will be passing following arguments to our hook:
sliderWidth (number)
knobWidth (number),
onDraggedSuccess (callback).
maxRange (number) - to track a current step, optional
initialValue (number) - if we want to set the initial position of knob inside a slider, optional
To show a more interesting example, we will animate Slider2 with our useSlider hook. The idea of this example comes from a slider, which already has been animated with Reanimated 1, by William Candilon in this video
Firstly, uncomment in App.js these lines:
import Slider2 from './Slider2';
<View style={{margin: 50}} />
<Slider2 />
In this part, we will add some rotation styling to our penguin and interpolate color of the progress bar. To achieve this we use the interpolate method from the Reanimated 2 library.
Interpolation helps you to create good animations by mapping input ranges to output ranges. We use it like this:
There is a handy way in Reaniamted2 to interpolate colors based on shared value changes. For that purpose, we use the interpolateColor method. Its way of working is similar to the interpolation method, except that this time our output array consists of colors. The creators of the library made sure that it is possible to pass colors in the most popular formats. Let’s use RGB format here.
This is the last part of the article. We will make a small experiment by moving our penguin programmatically by changing trasnlateX.value, in the button onPress method. Additionally, we will use timing functions from Reanimated 2.
Let’s take a look, how we can animate shared values by the withTiming method.
// Example usage of withTiming
// withTiming takes 3 arguments
// 1. new target value
// 2. animation config object
// 3. callback function, which will be executed right after the animation is complete
translate.value = withTiming(
300,
{
duration: 1000,
easing: Easing.linear,
},
() => {
// do sth
},
);
Reanimated 2 offers us more methods to create interesting animations like withSpring, withDelay, withRepeat, cancelAnimation, and more. I encourage you to give it a try. We have left a Slider3.js file, with a static slider. Feel free to make your experiment using Reanimated 2 API. Hope you guys have fun using it.
Conclusions
To start writing code with the new Reanimated 2 API, you don’t need to have prior experience with react-native-reanimated library. The library offers us the powerful API to create eye-catching and effective animations.
The first version of this article was created in August 2020 and used the alpha version. Since then, the library has been in the intensive development phase all the time. The developers have made every effort to ensure that the API was stable and did not cause errors. On the day of writing the article update, the library has a stable version (2.5.0) that can be safely used in production apps.
In my opinion, Reanimated2 will be setting new trends and will be the first choice by React Native developers when it comes to choosing a library for building animations.
By reading this article, you’ve gained some practical knowledge about how you can use the new Reanimated 2 API. I hope you’ve enjoyed reading it. For more examples, I refer you to the inspiring YT channel
Thank you! Your submission has been received! 📨
Oops! Something went wrong while submitting the form.
Share our work
React Native
Reanimated
Hooks
Animations
See related posts
Draggable elements with React-dnd
React
React Query
Mirage JS
Typescript
Shopping list with draggable UI elements and mocked backend with Mirage JS. React Query to sync UI with the backend.