Photo by @donramxn.

How to use Reanimated 2 (a beginners guide)

Spencer Carli
May 12 · 5 min read

Reanimated 2 is a hyper powerful library that all the cool kids use but has always been a bit of a blackbox to me… I saw the power of it but was overwhelmed by the API.

This post was originally published on React Native School. If you’re interested in hundreds of React Native tutorials and courses be sure to check it out!

Today I want to share with you what I’ve learned and we’ll create our first Reanimated 2 animation together — an image that changes sizes.

Let’s start with an app that renders a 100x100 image. All standard React Native.

import React from 'react';
import { View, TouchableOpacity, Image } from 'react-native';

export default () => {
return (
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'column',
backgroundColor: '#7CA1B4',
}}
>
<TouchableOpacity
onPress={() => {
alert('todo!');
}}
>
<Image
source={require('./rns.png')}
resizeMode="contain"
style={{ width: 100, height: 100 }}
/>
</TouchableOpacity>
</View>
);
};

We’ll be animating the size of the image. That means that we need to store the value to be animated somewhere.

Reanimated 2 has a concept of shared values. These are values that can be shared across different threads (think JavaScript thread and UI thread) thus the name of shared value.

It’s where you’ll want to store your “animateable” data — in this case the random number that we’ll use to drive the size of the image.

returns a value - similar to using on a hook - that means that we can't just access the result directly. We need to access the property of the returned data.

Also note in the following code that I’ve replaced the component with an . This is in preparation for when the value will change.

import React from 'react';
import { View, TouchableOpacity, Image } from 'react-native';
import Animated, { useSharedValue } from 'react-native-reanimated';

export default () => {
const randomNumber = useSharedValue(100);

return (
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'column',
backgroundColor: '#7CA1B4',
}}
>
<TouchableOpacity
onPress={() => {
alert('todo!');
}}
>
<Animated.Image
source={require('./rns.png')}
resizeMode="contain"
style={{ width: randomNumber.value, height: randomNumber.value }}
/>
</TouchableOpacity>
</View>
);
};

Now let’s go ahead and change that . Make sure you use when accessing the data.

import React from 'react';
import { View, TouchableOpacity, Image } from 'react-native';
import Animated, { useSharedValue } from 'react-native-reanimated';

export default () => {
const randomNumber = useSharedValue(100);

return (
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'column',
backgroundColor: '#7CA1B4',
}}
>
<TouchableOpacity
onPress={() => {
randomNumber.value = Math.random() * 350;
}}
>
<Animated.Image
source={require('./rns.png')}
resizeMode="contain"
style={{ width: randomNumber.value, height: randomNumber.value }}
/>
</TouchableOpacity>
</View>
);
};

But when we press the image nothing is happening… why?

It’s not changing because, unlike when calling , it doesn't cause a re-render to happen (which is good) we're just changing a value.

What we need to do is spawn a worklet that can adjust to changes in .

This worklet will run on the UI thread (rather than the JavaScript thread) allowing us to see a smooth native animation.

To spawn this worklet we’re going to use the hook. This hook will return a style object that updates with . This style object can then be applied to our .

is similar to but actually returns a value (the style object).

import React from 'react';
import { View, TouchableOpacity, Image } from 'react-native';
import Animated, {
useSharedValue,
useAnimatedStyle,
} from 'react-native-reanimated';

export default () => {
const randomNumber = useSharedValue(100);

const style = useAnimatedStyle(() => {
return { width: randomNumber.value, height: randomNumber.value };
});

return (
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'column',
backgroundColor: '#7CA1B4',
}}
>
<TouchableOpacity
onPress={() => {
randomNumber.value = Math.random() * 350;
}}
>
<Animated.Image
source={require('./rns.png')}
resizeMode="contain"
style={style}
/>
</TouchableOpacity>
</View>
);
};

Now when we press the image the size of it changes (granted it’s not animated — we’ll get to that).

The final piece of (this) puzzle is to actually animate the values. We’ve created all the necessary relationships between data and have things updating where they need to be — now we need to choose the animation to use.

Today we’ll make “springy”.

By importing we can tell Reanimated 2 how we want that data to change.

import React from 'react';
import { View, TouchableOpacity, Image } from 'react-native';
import Animated, {
useSharedValue,
useAnimatedStyle,
withSpring,
} from 'react-native-reanimated';

export default () => {
const randomNumber = useSharedValue(100);

const style = useAnimatedStyle(() => {
return {
width: randomNumber.value,
height: randomNumber.value,
};
});

return (
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'column',
backgroundColor: '#7CA1B4',
}}
>
<TouchableOpacity
onPress={() => {
randomNumber.value = withSpring(Math.random() * 350);
}}
>
<Animated.Image
source={require('./rns.png')}
resizeMode="contain"
style={style}
/>
</TouchableOpacity>
</View>
);
};

Alternatively we could use inside of to customize how each property changes.

import React from 'react';
import { View, TouchableOpacity, Image } from 'react-native';
import Animated, {
useSharedValue,
useAnimatedStyle,
withSpring,
} from 'react-native-reanimated';

export default () => {
const randomNumber = useSharedValue(100);

const style = useAnimatedStyle(() => {
return {
width: withSpring(randomNumber.value),
height: withSpring(randomNumber.value, { stiffness: 10 }),
};
});

return (
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'column',
backgroundColor: '#7CA1B4',
}}
>
<TouchableOpacity
onPress={() => {
randomNumber.value = Math.random() * 350;
}}
>
<Animated.Image
source={require('./rns.png')}
resizeMode="contain"
style={style}
/>
</TouchableOpacity>
</View>
);
};

And that’s on me trying to figure out the moving parts of Reanimated 2. To me it’s a pretty complex library to first learn but the power of it is incredible.

If you have any comments/corrections/questions please reach out on Twitter.

Originally published at https://www.reactnativeschool.com.

React Native School

Learn to build great React Native apps.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

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