Tutorial hero image
Lesson icon

Using the CreateAnimation Wrapper Component in an Ionic/React Application

3 min read

Originally published August 25, 2020

I've been working on a lot of animations with React and the Ionic Animations API as I create the React edition for Advanced Animations & Interactions with Ionic (which will be out sometime around October 2020 for those interested).

I already have a bit of content on the blog and my YouTube channel covering the basics of using the Ionic Animations API, but using it in an Ionic/React application is a little different to the usual experience. So, I wanted to create this tutorial to highlight the various ways you can create animations in React applications using the Ionic Animations API.

Throughout this tutorial, we will be building this simple animation two different ways:

One animation uses the <CreateAnimation> wrapper that the @ionic/react package provides, and the other animation uses the createAnimation method directly (which any framework can make use of an is available through @ionic/core). As you can probably tell, they both have the exact same result. The full source code for this tutorial will be available at the bottom of the page.

If you need more general context about the Ionic Animations API before we begin, I would recommend watching this video first: The Ionic Animations API.

Outline

Source code

The createAnimation Method

The main focus of this tutorial will be on creating an animation with the CreateAnimation component since it is React specific, but for context, let's also cover the "normal" method for creating animations with the Ionic Animations API. If you prefer this method, there is no need to use the CreateAnimation component at all.

To create the animation shown above, we would first import createAnimation from @ionic/react:

import { createAnimation } from '@ionic/react';

Then we would get a reference to the element we want to animate:

const Home: React.FC = () => {
  // Animation Method Two (createAnimation)
  const animationRef = useRef < HTMLDivElement > null;

  return (
    <IonPage>
      <IonHeader>
        <IonToolbar color="primary">
          <IonTitle>React Animations</IonTitle>
        </IonToolbar>
      </IonHeader>
      <IonContent>
        <div ref={animationRef} className="square"></div>
      </IonContent>
    </IonPage>
  );
};

export default Home;

Finally, we would use the createAnimation method to define and play our animation. You could do this in a hook like useEffect or you could trigger the animation through a method like this (e.g. when a click occurs):

const handlePlayAnimation = () => {
  if (animationRef.current !== null) {
    const animation = createAnimation()
      .addElement(animationRef.current)
      .duration(1000)
      .fromTo(
        'transform',
        'translateY(0) rotate(0)',
        'translateY(200px) rotate(180deg)'
      )
      .easing('ease-out');

    animation.play();
  }
};

We are both defining and playing the animation here, but if you wanted you could also set up the animation earlier (e.g. in a useEffect hook) and play it later by keeping a reference to the created animation.

The createAnimation method is generally the approach I prefer to use. However, the CreateAnimation component does provide some unique advantages for React applications.

The CreateAnimation Component

When using the Ionic Animations API with React, we have a bit of a unique approach that we can use. As well as the createAnimation method that we discussed above (which is what is typically used for other frameworks), we can also use the <CreateAnimation> wrapper component that the @ionic/react package provides for us.

The key difference with this component is that we can define and play our animation entirely in the template, with no need to hook into some logic to create the animation. You just surround the element you want to attach the animation to and it will have the animation attached to it:

<CreateAnimation /* animation properties defined as props here */>
  <div>I'm going to be animated!</div>
</CreateAnimation>

This isn't necessarily better or worse, it will just depend on the situation and your preferences as to what approach suits best, but it's definitely a nice option to have.

Let's take a look at how we might define the animation at the beginning of this post:

<CreateAnimation
  duration={1000}
  fromTo={{
    property: 'transform',
    fromValue: 'translateY(0) rotate(0)',
    toValue: `translateY(200px) rotate(180deg)`,
  }}
  easing="ease-out"
>
  <div className="square"></div>
</CreateAnimation>

This will define the animation, but it won't play it. In order to play the animation, you will need to add the play property and set it to true:

<CreateAnimation
  duration={1000}
  fromTo={{
    property: 'transform',
    fromValue: 'translateY(0) rotate(0)',
    toValue: `translateY(200px) rotate(180deg)`,
  }}
  easing="ease-out"
  play={true}
>
  <div className="square"></div>
</CreateAnimation>

What if you don't want to play the animation right away? One option you could use is to make use of useState to define a boolean that controls whether or not the play property is set to true:

const [playAnimation, setPlayAnimation] = useState(false);

// ...snip

<CreateAnimation
  duration={1000}
  fromTo={{
    property: 'transform',
    fromValue: 'translateY(0) rotate(0)',
    toValue: `translateY(200px) rotate(180deg)`,
  }}
  easing="ease-out"
  play={playAnimation}
>
  <div className="square"></div>
</CreateAnimation>;

Now as soon as you call setPlayAnimation(true) the animation will begin playing. However, just because we are defining the animation in the template, it doesn't mean that we loose access to that vast amount of API methods that the Ionic Animations API provides. Instead of doing the above to play the animation, we might also do it by calling the play method directly.

First, we would get a reference to the CreateAnimation component:

const animationRef = useRef < CreateAnimation > null;

// ...snip

<CreateAnimation
  ref={animationRef}
  duration={1000}
  fromTo={{
    property: 'transform',
    fromValue: 'translateY(0) rotate(0)',
    toValue: `translateY(200px) rotate(180deg)`,
  }}
  easing="ease-out"
>
  <div className="square"></div>
</CreateAnimation>;

and then if we use that reference inside of some other method or the useEffect hook we can call the play method directly:

if (animationRef.current !== null) {
  animationRef.current.animation.play();
}

You can even set up the entire animation using this method. You could just surround the element you want to animate with a <CreateAnimation> wrapper with no props:

<CreateAnimation ref={animationRef}>
  <div className="square"></div>
</CreateAnimation>

and then you could call the setupAnimation method to define the animation by passing the props to it:

if (animationOneRef.current !== null) {
  // Set up animation manually
  animationOneRef.current.setupAnimation({
    duration: 1000,
    fromTo: {
      property: 'transform',
      fromValue: 'translateY(0) rotate(0)',
      toValue: `translateY(200px) rotate(180deg)`,
    },
    easing: 'ease-out',
  });

  // Play animation with animation reference
  animationOneRef.current.animation.play();
}

You can also do more than just call the play method with the animation reference. You can call any method that the Ionic Animations API provides, e.g:

const animation = animationRef.current.animation;
animation.addElement();
animation.addAnimation();
animation.onFinish();
animation.beforeStyles();
animation.afterAddWrite();
// ...and so on

Summary

Using the Ionic Animations API is the same great experience as anywhere else, except with the added bonus of the optional <CreateAnimation> wrapper. Personally, I haven't been making much use of <CreateAnimation>, but that might just be because I'm used to using the Ionic Animations API the other way. If you're an Ionic/React developer, do you like the idea of using <CreateAnimation>? Leave a comment below!

If you enjoyed this article, feel free to share it with others!