Using the CreateAnimation Wrapper Component in an Ionic/React Application
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 codeThe 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!