You can't have missed it, Reanimated 2 is literally
everywhere. And that's for a reason since it's so great to use. What you might have realized too is
that many people show what they can do with it, but too little of us know how to use it
ourselves. So today, you will learn about how Reanimated 2 works for someone who has never
used it or know a little bit about Animated. All right, let's begin. Before we start, just a heads
up: in React Native, there's a way of animating elements using what they called Animated. Although
this video is about Reanimated which is a totally different library, I'll still make a few parallels
with the Animated API. So just try to remember, if I say Animated, I mean the built-in animation library,
not Reanimated. Just wanted to clear things out. When you want to animate a View opacity in React
Native, you might think of state: it starts with a default value that is later updated. The problem
with this is that the animation logic lies on the JavaScript side of things. If our application is
busy fetching data, loading a screen or if we're using a low-end device, the animation might
be very slow. The way this can be solved is by sending all the work to a separate box,
called the UI thread, which can do all the work smoothly since it works separately from
the main thread of the app. In Reanimated, they have this concept of "worklet", which just
means that some code written in JavaScript should run on the UI thread instead. This, is a
usual function running on the JavaScript thread. And this, is the same function running on the UI
thread when called. So I know this is weird but just remember that whenever a function starts with this
"worklet" string, it means that the following code will run in a separate box and therefore won't be
impacted by large computations on the JavaScript thread. Back to our state problem, Reanimated
actually have a way for your state to live on that UI thread. You can think of it as a useState
worklet, which does the same thing but inside that other box. So it isn't called state, but a "shared value".
They called it shared because you create it from the JavaScript thread, but it is then sent to the other
one. So the value gets shared between two threads, our two boxes. The "useSharedValue" Reanimated hook
lets you create an animated value in a single line, without any mention of a worklet. But remember
that's how it actually works behind the scenes. If you're coming from Animated, this works a
lot like an animated value, except that it can carry any type of data: numbers, booleans, objects...
anything. We'll keep the opacity at 0 for now, but you get the idea. All right, now there are two
things you still need to learn about shared values.Β One, is to get its current value, you can't
just call opacity like a state, but by using opacity.value. We'll get back to this later. If you
want to update that value, you might be tempted to call setValue just like in Animated but in
Reanimated you can change its value as you would with any other variable. Perfect. I mean,
we're much closer now from a great animation. Truth is at this point, our View won't know
how to deal with a shared value in its style because it isn't just a number. Just like in
Animated, where we need to turn the element into an animated one, that's our first step for React
Native to deal with this. Let's replace that View with an Animated.View that we get from Reanimated.
By the way, Reanimated has a few basic elements like Animated.Image, .ScrollView
etc. which comes really handy. Ok so that's where it gets tricky once again.
These elements with React Native Animated could understand animated values but, in Reanimated, you
can't just pass a plain object to an element. Because it is a shared value that lives in a
different box, and also because it will change over time and be manipulated, it is better if
all the computation happens also in that other box. The second thread can take care of generating the
styling, based on changes, dependencies and all of this won't happen on the JavaScript thread
which is a great boost for your animations. Just like you would call StyleSheet.create,
Reanimated has its own way of styling things with the "useAnimatedStyle" hook that takes
a function, that returns a style object. It feels different, doesn't it? The way you can
easily remember this is that, every style that won't animate can be created with a React Native
StyleSheet. However, if the style property changes based on a shared value, that's the case with
opacity here, then it needs to go through that hook. You might also have heard about interpolation,
and if not, I'll explain it briefly. Here we animate opacity from 0 to 1, and we might
also want to animate another style property based on the opacity value. If i want to increase
the View size when the opacity increases, I can do this by interpolating the opacity shared value.
I will need to map the opacity, to what the scale should equal to based on the current opacity value.
So here, the scale will be 0.5 when the opacity is 0, and 1 when it is 1. This is similar to
value.interpolate with Animated by the way. With this code, we animate the opacity, but also
scale the View up when that opacity goes to 1. And you know what? After all this work,
we're still not animating the way we should. But, using a shared value and an animated style,
you just prepared the whole ground for animating smoothly that opacity and any other property at
full speed on literally any device. By the way, quick note. You might be wondering: what if you
want to animate other properties, not just style. Some of you might know about the setNativeProps
in React Native which is not really recommended, but with Reanimated you can do
it in a better way with "useAnimatedProps". This works just like an animated style, but it
returns props that are computed on the UI thread. You might need this for animating SVG paths like this
one for example, but it will work for anything else. There is really a reason why everyone loves
Reanimated, and we're getting there so bear with me. If we go back to our
useEffect, I'll be honest with you: this is bad, slow and so not Reanimated style.
Here, we're setting a 25ms interval to update our shared value. The problem once again is
that, this will run on the JavaScript thread. With Animated, you probably remember Animated.timing
or .spring that handled that for you. The idea is to ask the UI thread to update your animated
value to a different one in an optimized way. Well, in Reanimated you can do the same thing
with shared values, and it is much simpler This, will update our opacity from 0 to 1, over
1 full second, all running on the UI thread. If you want a spring
animation, just use "withSpring". And this will automatically run a spring
animation for you on the opacity shared value. Of course, this is just a simple animation,
but there's a lot more that can be done in a few lines, just like delaying the
animation for 2 seconds let's say. You can also repeat it a
number of times, back and forth, and it'll actually know how to swing back
to the original value, again and again. You can even loop the animation forever. And if you
want a sequence of animations, that's possible too. The documentation is really great
if you want to get all the details, but here you have it, fast
animations on any device, in one line. Ok so by now, you know as much as I do that
in our daily apps, there are animations but also tons of gestures. If most of them are usually
handled by your navigation library, you might need to zoom on an image, reorder elements or play
with a bottom sheet. You can do this as well with Reanimated and again, it will run on the
UI thread so you're not losing in performance. Let's say we want to move this circle around,
on both the X and Y axes. You can achieve this with Reanimated combined with react-native-gesture-handler
which is a faster, more advanced version of a Pan Responder. I will create two shared values to
store our current touch position, one for each axis. This is necessary so that when we touch the
screen, we can reflect that touch movement on our View so that it moves along our touch. Now,
just like a Pan Responder, I will create a gesture handler which describes the logic of a gesture and
how our app should respond to these touch events. This handler will store the touch
position when the gesture is active, and then spring animate the value
to its initial position when it ends. That's all there is for the
logic. Now two more things: First, we need to move our View
according to our touch value. And because touchX and Y are shared values, if
we want to style a View based on their changes, remember that we can only do this through an
animated style. So let's add it to our current one. And for our View to react to our touch, we need
to wrap it with a PanGestureHandler, just so it knows which element events to listen to. Let's
import it from react-native-gesture-handler. Pretty cool isn't it? And the code is just
so simple, it's even too simple if you've ever struggled with PanResponder and
Animated before. If you're curious, you can play with other gestures handlers that the
library comes with, it's really neat and simple to integrate with Reanimated. Alright, last
stop and I promise we're done after this one, is about scroll handlers. It is very common to
animate something based on a scroll position. In our case, we could wrap our circle with a
a ScrollView, and whenever we scroll beyond the boundaries, the background color should turn grey. To do so,
we need to store the vertical scroll position somewhere, so we then can animate the background
color accordingly. Let's create a shared value for this and a scroll handler that will update the
value whenever we move the ScrollView. Of course we need to attach this handler to the ScrollView
itself, that will turn into an animated one as well. Perfect, we have the scroll position now and can
interpolate it to the ScrollView background color. For this, we'll need to turn a number into a color.
Since the interpolate function can only return numbers, this will not work. That's actually a
little difference with Animated but anyways, let's use "interpolateColor" this time. It interpolates
a shared value and turns it into a color. So what this says is when the
vertical scroll is at 0, meaning at the initial position, the
color should be white. But whenever we start scrolling up or down within 50 pixels, we
should interpolate scrollY into shades of gray. (ok that one was intended!) Anyways, we
just animated this background color based on the scroll position and again, it's all
running on the UI thread without any extra effort. We've learned quite a few things
today, so let's sum this up. useSharedValue stores any data that is
meant to change over the component life cycle. This works pretty much like
state, but on the UI thread. useAnimatedStyle works like a StyleSheet, except
that it is meant to return an animated style. Every component style property that should be animated or
that depends on a shared value should end up there. interpolate takes a shared value, a range of
possible values (called the input range) and map them to other outputs. It basically computes
a new value based on the current progress of a shared value. When you want to interpolate a shared
value into colors, use interpolateColor instead. Now looking at animations, withTiming, withSpring,
withDecay are three simple ways of animating shared values from one value
to another. They can be delayed, repeated or put in a sequence. Lastly, gestures, either using
the handlers from react-native-gesture-handler: Pan, Pinch, LongPress etc. or a
simple scroll handler. Alright, this was a quick tour of Reanimated. It is by far,
the easiest way of creating complex animations and if you don't know where to begin with, you
can expect a lot more of it on this channel. Remember to subscribe if you don't want to missΒ
it. Thanks for watching and see you next time :)
Only feedback is that we want more of your tutorials!
Woah. As someone who has a course on Reanimated 2 and I can only commend you for making such high-quality content. Congratulations!
Very cool content :)
Thank you. Will check it out
You did a great job with this video!
I thought this was very, very good. How long does something like this take to put together? Did you find it helped your own understanding of Reanimated when putting the video together?
Great job!
Man, your YT and Medium content is something I`ve been searching for for a while now -Animations are definitely my weakest spot in RN development. Big thanks for posting it here!
I love your video! One tiny feedback - when demonstrating the animation, you could show the tap on your device. This was a little confusing when you were demonstrating the part where the dragged circle bounces back to its original position.
For convenience, there's an article detailing how to do this on the simulator and the actual iPhone device.
I always appreciate these kind of tutorials. Thanks a lot for taking from your time to give us this