Adding animations to your React Native app - Part 1: Basic Animations
Tags: reactnative, animations
Published: 2019-07-09 03:45:32

---
title: Adding animations to your React Native app - Part 1: Basic Animations
published: true
description: In this tutorial you'll learn how to implement basic animations in React Native
tags: [react-native, animations]
series: Adding animations to your React Native app
canonical_url: https://blog.pusher.com/animation-react-native-part-1/
---

Animations are an important part of the user experience, especially for mobile apps. Animations provide users with a clear feedback when they’re interacting with the UI elements in the app. Animations bring the app to life through the use of movement.

Whenever the app needs to perform a long operation, animations can be used to entertain the user. At the same time, it can also be used to inform the user of the operation’s status. Most importantly, animations can be used to teach the user how to interact with the app. This is through the use of meaningful transitions when hiding or showing UI elements.

In this series, we’ll be taking a look at how we can implement animations in a React Native app. In each part, you will learn the following:

- How to implement basic animations such as scale, spring, and transform.
- How to implement transition animations when users navigate from one page to another.
- How to implement gesture animations when users interact with UI elements.

## Prerequisites

In order to follow this tutorial, you must have basic knowledge of React and React Native. This tutorial assumes that you have a working knowledge of the following concepts:

- State
- Refs and Props
- Component lifecycle methods
- Class-based and functional components

Aside from that, you should also be familiar with some ES6 features. Things like object destructuring and spread operator.

I also assume that your computer is set up for React Native development. If you’re using [Expo](https://expo.io/), you can also follow along as this tutorial doesn’t require the use of any native modules. But I’ll let you handle the modifications required to get the app running.

## What you’ll be building

Throughout the whole series, we’re going to build just a single app. We will be adding the animations mentioned above as we go along.

On the first part of the series, here’s what the final output is going to look like:

![Pokemon Gallery part one demo (Image credit: pokemondb.net and pokeapi.co)](https://d2mxuefqeaa7sj.cloudfront.net/s_E4AC20E49A0067C1947CB6DF434358FF2AEC2028FB0038226D770EAC1C5A6720_1529155782472_rn-animations-part1-demo.gif)

The app is going to be a Pokemon gallery app where users can view the details of a Pokemon. The app will have minimal functionality to keep the focus on animation.

## Setting up the project

In order for us to get to the animation part as soon as possible, I’ve already set up a [React Native project](https://github.com/anchetaWern/RNRealworldAnimations) which has all the screens and components that the app requires. You can clone it using the command below:

```
git clone https://github.com/anchetaWern/RNRealworldAnimations.git
```

The repo defaults to the `master` branch which contains the final output for the whole series. Switch to the `starter` branch so you can follow along with this part of the series:

```
cd RNRealworldAnimations
git checkout starter
```

After switching, install all the required packages:

```
npm install
```

Next, execute the following in order to add the `android` and `ios` directories:

```
react-native upgrade
```

The project uses [React Native Vector Icons](https://github.com/oblador/react-native-vector-icons), and it needs to be linked to the native project, so execute the following as well:

```
react-native link
```

Once it’s done installing, you should be able to run the app on your emulator or device:

```
react-native run-android
react-native run-ios
```

## Scale animation

The first type of animation we’re going to implement is a scale animation and it looks like this:

![Scale animation](https://d2mxuefqeaa7sj.cloudfront.net/s_E4AC20E49A0067C1947CB6DF434358FF2AEC2028FB0038226D770EAC1C5A6720_1529156972093_button-press-scale-animation.gif)

What we want to do is to scale up the size of the card as the user is pressing the card. We then scale it back down once they release it. The component that we will be working on is the `Card` component (`src/components/Card.js`).

Animations in React Native can be implemented through the following steps:

1.  Import the animation modules.
2.  Declare an animated value.
3.  Specify how the animated value will change over time.
4.  Set the animated style and render an animated version of the component.
5.  Start the animation.

The first step is to import the animation modules. React Native already provides modules that allow us to add animations to our apps, go ahead and import them:

```javascript
// src/components/Card.js
import {
  // previously imported modules
  Animated, // provides methods for animating components
  Easing // for implementing easing functions
} from "react-native";
```

Next, declare an animated value. In a functional component like the `Card` component, this can be done right before you return the component to be rendered:

```javascript
const Card = ({
  // props destructuring
}) => {
  let scaleValue = new Animated.Value(0); // declare an animated value
```

In the above code, we’re initializing an animated value to zero. Most of the time, this is what you’ll want to do. This is because every component always starts out as static, they only move once the user interacts with it or it becomes visible in the foreground. The updating of this animated value is what allows us to move components as you’ll see later on. It has the same idea as the _state_ though animated values are specifically used for animations.

The next step is to specify how the animated value will change over time. All animated values come with an `interpolate` method which allows us to update its value once the animation is started. This method accepts an object containing an `inputRange` and `outputRange` properties. Each one has an array value which maps to one another:

```javascript
const cardScale = scaleValue.interpolate({
  inputRange: [0, 0.5, 1],
  outputRange: [1, 1.1, 1.2]
});
```

When I said “maps to one another”, I mean this:

- 0 → 1
- 0.5 → 1.1
- 1 → 1.2

We’ve already initialized the animated value to `0`. This is one of the values we’ve specified in the `inputRange`, and the corresponding `outputRange` value for that is `1`. The `outputRange` in this case refers to the scale factor of the component. `1` means it’s the same as its original size because any integer that you multiply by 1 will always be equal to itself.

Next, is `0.5` is to `1.1`. This means that when the animation gets halfway through its peak, we want to scale the component so it’s 10% bigger than its original size. And by the time the animation reaches its peak, we want it to be 20% bigger. Note that we only need to specify a sample for the input and output ranges. The animation library will automatically figure out anything in between the numbers you specified. This ensures that the animation is as smooth as possible.

The next step to implement the animation is to set the animated style and render an animated version of the component. All you have to do is to replace `<View style={styles.card}>` with `<Animated.View style={transformStyle}>`. So you’re essentially wrapping the entire contents of the `Card` component with `Animated.View`. Here’s what that looks like in code:

```javascript
let transformStyle = { ...styles.card, transform: [{ scale: cardScale }] };

return (
  <TouchableWithoutFeedback>
    <Animated.View style={transformStyle}>
      <Image source={item.pic} style={styles.thumbnail} />
      <Text style={styles.name}>{item.name}</Text>
      <View style={styles.icons}>
        <IconButton
          icon="search"
          onPress={() => {
            viewAction(item.name, item.full_pic);
          }}
          data={item}
        />
        <IconButton icon="bookmark" onPress={bookmarkAction} data={item} />
        <IconButton icon="share" onPress={shareAction} data={item} />
      </View>
    </Animated.View>
  </TouchableWithoutFeedback>
);
```

On the first line of the code above, we’re creating a new `style` object composed of the card’s default style (`styles.card`) and the transform styles. If you’re familiar with CSS animations, this should make sense to you. But if not, the code above is using a CSS `scale` transform declaration to scale the size of the card based on the current value of the animated value.

When you render an animated component, you should use the animated version. React Native comes with three primitive components: `View`, `Text`, `Image` and `ScrollView`. To use the animated versions of these, all you have to do is prefix them with `Animated`, so `View` becomes `Animated.View` and so on.

The last step to implement the animation is to actually start it. In the starter code, the `Card` component is using the `onPress` event handler. And yes, we can actually start the animation from there:

```javascript
<TouchableWithoutFeedback
  onPress={() => {
    scaleValue.setValue(0);
    Animated.timing(scaleValue, {
      toValue: 1,
      duration: 250,
      easing: Easing.linear,
      useNativeDriver: true
    }).start();

    cardAction();
  }}
/>
```

The only problem is that the code above doesn’t really take into consideration when the user is holding down the component. If you try to run it, the component will simply go back to its original size even while the user is still holding it down.

Thankfully, the `TouchableWithoutFeedback` component already comes with an `onPressIn` and `onPressOut` [event handlers](https://facebook.github.io/react-native/docs/touchablewithoutfeedback.html#onpressin). This allows us to capture when the user is holding down the button or when they already released it:

```javascript
<TouchableWithoutFeedback
  onPressIn={() => {
    scaleValue.setValue(0);
    Animated.timing(scaleValue, {
      toValue: 1,
      duration: 250,
      easing: Easing.linear,
      useNativeDriver: true
    }).start();

    cardAction();
  }}
  onPressOut={() => {
    Animated.timing(scaleValue, {
      toValue: 0,
      duration: 100,
      easing: Easing.linear,
      useNativeDriver: true
    }).start();
  }}
>
```

Breaking down the code above, first, we go through the body of the `onPressIn` method. First, we set the animated value to `0`. This effectively resets the animation everytime the user initiates it:

```javascript
scaleValue.setValue(0);
```

Next, we start the animation by using the `timing` animation. This allows us to update the animated value over a specific period of time. This method accepts two arguments: an animated value, and an object containing the settings to use for the animation.

In the code below, we’re telling it to update the animated value to `1` over the course of `250` milliseconds and it will use the `linear` easing function:

```javascript
Animated.timing(scaleValue, {
  toValue: 1, // update the animated value to
  duration: 250, // how long the animation will take in milliseconds
  easing: Easing.linear, // easing function to use (https://facebook.github.io/react-native/docs/easing.html)
  useNativeDriver: true // delegate all the animation related work to the native layer
}).start(); // start the animation
```

When the user releases the component, all we have to do is bring back the animated value to its initial value over a specific period of time. This effectively reverses the animation by scaling back the size of the component:

```javascript
onPressOut={() => {
  Animated.timing(scaleValue, {
    toValue: 0, // reset the animated value to 0
    duration: 100, // animate over 100ms
    easing: Easing.linear,
    useNativeDriver: true
  }).start();
}}
```

Note that when you’re working with animations that are triggered by user controls, you want to use React Native components that don’t already have built-in animation behavior. In the case of a button, React Native also has `Button`, `TouchableOpacity` and `TouchableNativeFeedback` components. These are all pretty much the same, but they all have built-in animation behavior when a user interacts with them. That’s why we used `TouchableWithoutFeedback` to have full control over the animation without the need to override built-in behavior.

## Rotate animation

The next type of animation is a rotate animation and it looks like this:

![Rotate animation](https://d2mxuefqeaa7sj.cloudfront.net/s_E4AC20E49A0067C1947CB6DF434358FF2AEC2028FB0038226D770EAC1C5A6720_1529157038546_button-press-rotate-animation.gif)

Here we want to rotate or spin the buttons whenever the user presses on it. It has the same mechanics as the scale animation of the `Card` component earlier, the only difference is that we’re rotating the component instead of scaling it.

This time, we’ll be working with the `IconButton` component (`src/components/IconButton.js`). `IconButton` is a class-based component, and the best place to declare an animated value is inside the `constructor`:

```javascript
constructor(props) {
  super(props);
  this.rotateValue = new Animated.Value(0); // declare animated value
}
```

Inside the `render` method, we specify how the animated value will change. Since we’re doing a rotate animation, the `outputRange` is different. This time, we’re using a string value which specifies the degrees the animated value will rotate:

```javascript
render() {
  const { icon, onPress, data } = this.props;

  let rotation = this.rotateValue.interpolate({
    inputRange: [0, 1],
    outputRange: ["0deg", "360deg"] // degree of rotation
  });
  // next: add transformStyle  
}
```

Next, declare the styles for rotating the component:

```javascript
let transformStyle = { transform: [{ rotate: rotation }] };
```

Render the component:

```javascript
<TouchableWithoutFeedback
  onPressIn={() => {
    Animated.timing(this.rotateValue, {
      toValue: 1,
      duration: 700,
      easing: Easing.linear
    }).start();
    onPress(data);
  }}
  onPressOut={() => {
    Animated.timing(this.rotateValue, {
      toValue: 0,
      duration: 350,
      easing: Easing.linear
    }).start();
  }}
>
  <Animated.View style={transformStyle}>
    <Icon name={icon} style={styles.icon} size={icon_size} color={icon_color} />
  </Animated.View>
</TouchableWithoutFeedback>
```

As you can see from the code above, the code for starting and stopping the animation is pretty much the same as the scaling animation. We animate towards the desired value when the user interacts on it, then we reverse it when the user releases.

Another thing to notice is that we’re not animating the component itself, but its child (`Animated.View`). Note that the component that’s being animated doesn’t always need to be a child of the component being interacted upon (`TouchableWithoutFeedback`). It can be anywhere else in the render tree. As long as the component you want to animate is currently being rendered (it doesn’t have to be visible), you can animate it.

## Spring animation

The next type of animation is a spring animation and it looks like this:

![Spring animation](https://d2mxuefqeaa7sj.cloudfront.net/s_E4AC20E49A0067C1947CB6DF434358FF2AEC2028FB0038226D770EAC1C5A6720_1529157484072_modal-spring-animation.gif)

This time, we’ll be working with the `AnimatedModal` component (`src/components/AnimatedModal.js`). Currently, it’s not “Animated” yet so let’s go ahead and do that.

Unlike the two previous components we’ve worked with so far, this one relies on the _state._ If you open the `App.js` file, the modal is opened when `isModalVisible` is set to `true`:

```javascript
viewAction = (pokemon, image) => {
  // ...
  this.setState({
    // ...
    isModalVisible: true
  });
};
```

Then inside the `render` method of `AnimatedModal`, by default, we set its `bottom` value to be equal to the negative value of the screen’s height. This effectively hides the component from view. When `isModalVisible` is set to `true` the `bottom` value is updated to `0`. This returns the component back to its original position:

```javascript
import {
  /* previously imported modules here */
  Animated, // add this
  Easing // add this
} from "react-native";
const { height, width } = Dimensions.get("window");

type Props = {};
export default class AnimatedModal extends Component<Props> {
  render() {
    const { title, image, children, onClose } = this.props;
    let bottomStyle = this.props.visible ? { bottom: 0 } : { bottom: -height }; // show or hide the component from view
  }
}
```

This works, but there’s really no animation taking place when the component is hidden or shown from view. Let’s go ahead and fix this:

```javascript
constructor(props) {
  super(props);
  this.yTranslate = new Animated.Value(0); // declare animated value for controlling the vertical position of the modal
}
```

Inside the `render` method, specify how the `bottom` value will change once the animation is started. In this case, we want the animated value (`yTranslate`) to be `0` at the beginning of the animation. And it will become a specific height once it finishes:

```javascript
render() {
  const { title, image, children, onClose } = this.props;

  let negativeHeight = -height + 20;
  let modalMoveY = this.yTranslate.interpolate({
    inputRange: [0, 1],
    outputRange: [0, negativeHeight]
  });

  let translateStyle = { transform: [{ translateY: modalMoveY }] }; // translateY is the transform for moving objects vertically
  // next: render the component
}
```

Breaking down the code above, first, we need to determine the final `bottom` value once the animation finishes. Here, we’re getting the negative equivalent of the screen’s height and adding `20`:

```javascript
let negativeHeight = -height + 20;
```

But why? If you scroll down to the styles declaration of the component, you’ll find that the `bottom` value is set to the negative equivalent of the screen’s height:

```javascript
const styles = {
  container: {
    position: "absolute",
    height: height,
    width: width,
    bottom: -height, // look here
    backgroundColor: "#fff"
  }
  // ... other styles
};
```

So translating the `Y` position (vertical position) of the component to `-height` means that it will cancel out the `bottom` value declared in the styles. Remember that when two negative values are subtracted, they cancel each other out because the subtrahend (number on the rightmost portion of the equation) is converted to a positive number and the operation becomes addition:

```javascript
translateY = -1 - -1;
translateY = -1 + 1;
translateY = 0;
```

This effectively brings the component back to its original position. The `20` that we’re adding is the height of the uppermost portion of the screen (where the battery, time, and signal is indicated). We don’t really want the modal to replace those.

Next, apply the `translateStyle` to the component:

```javascript
return (
  <Animated.View style={[styles.container, translateStyle]}>
    <Header title={title}>
      <TouchableOpacity onPress={onClose}>
        <Text style={styles.closeText}>Close</Text>
      </TouchableOpacity>
    </Header>
    <View style={styles.modalContent}>{children}</View>
  </Animated.View>
);
```

On the modal’s header, we have a `TouchableOpacity` which allows us to close the modal. This executes the `onClose` method passed as a _prop_ from the `App.js` file:

```javascript
<AnimatedModal
  title={"View Pokemon"}
  visible={this.state.isModalVisible}
  onClose={() => {
    this.setState({
      isModalVisible: false
    });
  }}
>
  ...
</AnimatedModal>
```

Having done all the necessary setup, how do we actually start the animation? We know that the animation should be started when the value of `isModalVisible` is updated. But how do we know when the _state_ is actually updated? Well, we can use the `componentDidUpdate` lifecycle method to listen for when the component is updated. This function is called every time the _state_ is updated because we’re using a _prop_ which relies on the _state’s_ value (`visible`).

Here’s the code:

```javascript
componentDidUpdate(prevProps, prevState) {
  if (this.props.visible) {
    // animate the showing of the modal
    this.yTranslate.setValue(0); // reset the animated value
    Animated.spring(this.yTranslate, {
      toValue: 1,
      friction: 6
    }).start();
  } else {
    // animate the hiding of the modal
    Animated.timing(this.yTranslate, {
      toValue: 0,
      duration: 200,
      easing: Easing.linear
    }).start();
  }
}
```

There’s nothing really new with the code above, aside from the fact that we’re starting the animation from a lifecycle method instead of from an event handler. Another is that we’re using a spring animation. This is similar to the `timing` animation, though it differs in the options that you pass to it.

The spring animation only requires you to pass `toValue` for the options, but here we’re passing the `friction` as well. This allows us to specify how much friction we apply in the spring. The higher `friction` means less spring or bounciness. The value we specified is close to the default value which is `7`. This adds just a little bit of spring to the upward motion as the modal becomes visible:

```javascript
Animated.spring(this.yTranslate, {
  toValue: 1,
  friction: 6 // how much friction to apply to the spring
}).start();
```

You might be wondering why we created our own modal component instead of React Native’s [Modal component](https://facebook.github.io/react-native/docs/modal.html). That’s because it already comes with [animation capabilities](https://facebook.github.io/react-native/docs/modal.html#animationtype). But the downside is that it’s hard to customize the animation because the default behavior gets in the way.

## Width animation

The next type of animation is width animation and it looks like this:

![Width animation](https://d2mxuefqeaa7sj.cloudfront.net/s_E4AC20E49A0067C1947CB6DF434358FF2AEC2028FB0038226D770EAC1C5A6720_1529157554455_width-animation.gif)

In the above demo, we’re animating the width of the bar which represents the individual stats of the Pokemon.

This time, open the `src/components/AnimatedBar.js` file. If you run the app right now, the bars should just be static. What we’ll do is animate it from a width of `0` to its proper width.

Start by declaring the animated value:

```javascript
constructor(props) {
  super(props);
  this.width = new Animated.Value(0);
}
```

Then in the `render` method, we set the component’s `width` to be equal to the animated value:

```javascript
render() {
  let barWidth = {
    width: this.width
  };
  return <Animated.View style={[styles.bar, barWidth]} />;
}
```

Yeah, that’s right. In the code above, we don’t actually need to specify how the animated value will change over time. Using the `interpolate` method is optional if all we need to animate is the component’s `width`, `height`, `margin`, or `padding`. You can still use it if you want to have fine control over how the animated value will change. But since the `width` is a very linear property, we don’t really need to do that. Plus the animation looks better if the width changes in uniform fashion over time.

Next, create a function which will start the animation. So that the width for each bar doesn’t get animated at the same time, we’re adding a `delay` that is based on the current index. The first stat (HP) will have an `index` of `0` so there’s no delay. The second one will have a 150-millisecond delay, the third one will be twice as that and so on. This allows us to achieve the cascading effect that you saw on the demo earlier:

```javascript
animateBar = () => {
  const { value, index } = this.props;
  this.width.setValue(0); // initialize the animated value
  Animated.timing(this.width, {
    toValue: value,
    delay: index * 150 // how long to wait before actually starting the animation
  }).start();
};
```

We start the animation when the component is mounted and when its _props_ are updated:

```javascript
componentDidMount() {
  this.animateBar();
}

componentDidUpdate() {
  this.animateBar();
}
```

You might be asking why we need to start the animation on both `componentDidMount` and `componentDidUpdate`. Well, the answer is that the component is only mounted once when the app is started. This is because its parent (`AnimatedModal`) is always rendered. It’s just hidden from view because of the negative `bottom` value. On the first time the `AnimatedModal` is opened, the `componentDidMount` function in the `AnimatedBar` is executed. But for the succeeding views, only the `componentDidUpdate` function is executed.

Also, note that we’re updating the value of the stats every time the modal is opened. This allows us to still animate the `width` even if the user viewed a specific Pokemon twice in a row:

```javascript
// pre-written code on the App.js file
viewAction = (pokemon, image) => {
  this.pokemon_stats = [];
  pokemon_stats.forEach(item => {
    this.pokemon_stats.push({
      label: item,
      value: getRandomInt(25, 150)
    });
  });
};
```

Next, right below the `mainContainer` on the `BigCard` component, make sure that the `renderDataRows` function is being called. This function renders the `DataRow` component which in turn renders the `AnimatedBar`:

```javascript
// src/components/BigCard.js
render() {
  /* previously written animation code here */

 return (
  <View style={styles.container}>
    <View style={styles.mainContainer}>
      ...current contents here
    </View>
  </View>
  {data && (
    <View style={styles.dataContainer}>{this.renderDataRows(data)}</View>
  )}
}
```

The last step is to make sure the `AnimatedBar` is rendered inside the `DataRow` component. The code for that is already pre-written, so all you have to do is make sure `<AnimatedBar>` is rendered somewhere inside the `src/components/DataRow.js` file.

## Sequence animation

The last type of animation that we’re going to look at is the sequence animation and it looks like this:

![Sequence animation](https://d2mxuefqeaa7sj.cloudfront.net/s_E4AC20E49A0067C1947CB6DF434358FF2AEC2028FB0038226D770EAC1C5A6720_1529157684074_sequence-animation.gif)

There’s a lot happening in the demo above, so let’s break it down. A sequence animation is basically a collection of different animations that are executed one after the other. In the demo above, we’re performing the following animations in sequence:

- **Opacity animation** - changes the Pokemon’s big image from an opacity of zero to one.
- **Translate animation** - changes the position of the title. Starting from the top up to its proper position below the big Pokemon image.
- **Scale animation** - scales the size of the Pokemon’s name.

You already know how to implement the last two animations so I’m not going to explain the code for implementing those in detail. Also, note that this last animation is a bit over the top and you don’t really want to be doing this in a real-world app.

With that out of the way, let’s begin. Open the `src/components/BigCard.js` file and declare the three animated values that we will be working with:

```javascript
import {
  /* previously imported modules */ Animated,
  Easing
} from "react-native";

export default class BigCard extends Component<Props> {
  // add the code below
  constructor(props) {
    super(props);
    this.imageOpacityValue = new Animated.Value(0);
    this.titleTranslateYValue = new Animated.Value(0);
    this.titleScaleValue = new Animated.Value(0);
  }
}
```

Inside the `render` method, we specify how those three values will change. Interpolating the opacity is pretty much the same as how you would interpolate the scale or the vertical position of a component. The only difference is the style. In the code below, we’re setting the `opacity` to that interpolated value. This is very similar to how we animated the `width` for the Pokemon status bars earlier:

```javascript
render() {
  const { image, title, data } = this.props;
  // interpolate the images opacity
  const imageOpacity = this.imageOpacityValue.interpolate({
    inputRange: [0, 0.25, 0.5, 0.75, 1],
    outputRange: [0, 0.25, 0.5, 0.75, 1]
  });
  // construct the image style
  const imageOpacityStyle = {
    opacity: imageOpacity
  };
  // interpolate the vertical position of the title
  const titleMoveY = this.titleTranslateYValue.interpolate({
    inputRange: [0, 1],
    outputRange: [0, 280]
  });
  // interpolate the scale of the title
  const titleScale = this.titleScaleValue.interpolate({
    inputRange: [0, 0.5, 1],
    outputRange: [0.25, 0.5, 1]
  });
  // construct the styles for the title
  const titleTransformStyle = {
    transform: [{ translateY: titleMoveY }, { scale: titleScale }]
  };

  // next: render the component
}
```

Next, we render the component and assign the interpolated styles:

```javascript
return (
  <View style={styles.container}>
    <View style={styles.mainContainer}>
      <Animated.Image
        source={image}
        style={[styles.image, imageOpacityStyle]}
        resizeMode={"contain"}
      />
      <Animated.View style={[styles.titleContainer, titleTransformStyle]}>
        <Text style={styles.title}>{title}</Text>
      </Animated.View>
    </View>
    ...previous code here
  </View>
);
```

Note that the `titleContainer` has a `top` value of `-100`. This is the starting position of the title. If you have noticed in the demo earlier, this results in the title being directly below the current local time:

```javascript
const styles = {
  // .. other styles
  titleContainer: {
    position: "absolute",
    top: -100
  }
  // .. other styles
};
```

We start the animation when the component is updated. If you open the `App.js` file, you’ll see that the `BigCard` component relies on the current value of the _state_ for three of its _props_. This allows us to use `componentDidUpdate` to listen for changes in the _state:_

```javascript
<BigCard
  title={this.state.pokemon}
  image={this.state.image}
  data={this.state.stats}
/>
```

Going back to the `BigCard` component, here’s the code for `componentDidUpdate`:

```javascript
componentDidUpdate() {
  // reset the animated values
  this.imageOpacityValue.setValue(0);
  this.titleTranslateYValue.setValue(0);
  this.titleScaleValue.setValue(0);

  // start the sequence
  Animated.sequence([
    Animated.timing(this.imageOpacityValue, {
      toValue: 1,
      duration: 1000,
      easing: Easing.linear
    }),
    Animated.timing(this.titleTranslateYValue, {
      toValue: 1,
      duration: 300,
      easing: Easing.linear
    }),
    Animated.timing(this.titleScaleValue, {
      toValue: 1,
      duration: 300,
      easing: Easing.linear
    })
  ]).start();
}
```

Breaking down the code above, first, we reset the individual animated values, then we start the sequence animation. The `sequence` method accepts an array of animations. In this case, we’re only using timing animations, but you can actually mix in [spring](https://facebook.github.io/react-native/docs/animated.html#spring) and [decay](https://facebook.github.io/react-native/docs/animated.html#decay). Another difference is that we only start the sequence animation itself, not the individual animations inside it.

Of course, you can use the same method that we did earlier with the width animations wherein we added a `delay` setting. The `sequence` method doesn’t really allow you to specify the delay between each animation. If you want that, then there’s the [stagger](https://facebook.github.io/react-native/docs/animated.html#stagger) method.

## Conclusion

That’s it! In the first part of this series, you’ve learned how to implement basic animations using React Native’s `Animated` API. As you have seen, implementing animations in React Native is very code-heavy. This is because it doesn’t come with components that allow you to easily implement even the most basic types of animations. But that’s the price we have to pay for having finer control over how the animations will proceed.

We haven’t actually covered all the animation functions that the Animated library provides. Specifically, we haven’t covered:

- Animated.decay
- Animated.parallel
- Animated.stagger

Be sure to check out the [docs](https://facebook.github.io/react-native/docs/animated.html) if you want to learn about those.

You can check the final source code for this part of the series on its own [branch](https://github.com/anchetaWern/RNRealworldAnimations/tree/part1) (`part1`).

Stay tuned for the next part where we will look at how to implement page transition animations.

_Originally published on the [Pusher blog](https://blog.pusher.com/animation-react-native-part-1/)_