So I don't know if you've heard,
but there's this framework called react which is quite popular. There are also
some popular declarative animation libraries out there that are made
specifically for react. Now, GSAP isn't just for react, it's framework agnostic,
so you can use it anywhere. If you're one of the devs out there
that uses react and GSAP together, you'll know that animating imperatively gives you
a lot more power, control, and flexibility. You can reach for GSAP to
animate anything from DOM transitions to SVG, three JS canvas or WebGL, and
the limits are basically just in your imagination. However, if you are one of
the devs that uses GSAP and React, you will also know that there are
a few react specific pain points with animation. So we've created a new react
package with a useGSAP hook to make your lives easier. In this video,
we're going to be taking a look at why it's our recommended route, and
also how to use it. useGSAP's a handy drop in replacement for useEffect
or useLayoutEffect. It handles cleanup for you automatically, so you can just
focus on the fun stuff. It's safe to use in SSR frameworks, and also
allows you to easily scope animations within a container. It also lets you
easily react to changes in state. Most component based JavaScript frameworks
require animation cleanup. Cleanup is usually necessary when a component
unmounts, as you don't want animations sticking around and using up memory. But
react is a little bit different, as we don't have an unmounted event to
hook into, we have effects instead, and effects can get torn down both when
the component unmounts or if the dependencies change. There's also an
additional gotcha. So react 18 runs in strict mode locally by default, and strict
mode runs an extra setup and cleanup cycle on load. Basically, your effect runs
gets torn down, and then runs again. Any GSAP code inside your effect gets
executed twice. This can be a little bit of a surprise, it's caught out
quite a few people, so if you've run into this frustration before, you're
not alone. So how do we clean up properly? For most other frameworks, we
recommend using GSAP context. I've made a video on context
before, so I'll add that in the links below or floating around somewhere
here if you want to dive in. But in short, context basically collects
up all of your GSAP animations so that you can clean them up with
one line of code rather than trying to store all of your animations
individually and then revert them all one by one. So in Reactland, before we
had the useGSAP hook, we would pop a context inside of an effect
like this. We also had to remember to add in an empty dependency array
so that our animations didn't get called on every render. And then if we
were using a server side rendered framework like nextjs, we needed to use
this very awkwardly named bit of nonsense. useIsomorphicLayout effect. So you can
see how wordy this whole code snippet has got. It's not the nicest. So
we've abstracted all of this away into a hook. So now we just import
GSAP in the usual way. Then we import the useGSAP hook from the
react package, and then pop our GSAP code inside the hook. This is the
hook in its most basic form. Any GSAP code inside the function when it
executes will get reverted automatically when the hook's torn down. Revert is
basically like kill, except it returns your elements to their pre animation
state. This is important because it goes along with react's best practises. So at
the moment, we've just got a tween in here. But useGSAP handles cleanup
for all of your GSAP bits and bobs. So tweens, timelines, scroll
triggers, draggables, split text instances, all sorted out for you. Much
like the rest of the GSAP API, there's a handy config object that you
can parse in if you need a little bit more flexibility. So let's take
a little look at the config and how to scope your animations. So in
this example, we've got a nested component that we're adding some animations to. So
we've got a box and a circle in the nested component with classes of
box and circle, and then the same elements in the main app here with
the same classes. So now we're currently animating this circle with a ref. So
refs are great, they're super reliable for animation. You know exactly what element
you're getting. You can see this one's animating, and this duplicate element with
the same class isn't - so great. Now, if we were to use a class,
let's target the box class. The obvious issue is that the selector is going
to grab all of the boxes no matter which component they're in. So this
isn't ideal in a component based system, but we can pass in a scope
to keep the animations within a component. So let's pass this container in as
the scope and wahey, no more leaking animation. Now you may still
choose to use refs for something like this, where you only have a small
number of elements, but selectors and scoping can be super useful if you've
got a lot of elements in a predictable layout. So for stuff like
staggers, we see people doing stuff like this a lot where they just want
to stagger some elements, but they end up drowning in a sea of refs.
Now you could create an array of refs here, but that involves changing how
your JSX is structured and mapping around, which might not be ideal. So let's
pop back to the ref chaos and refactor this using a scoped container. So
let's get rid of all of this and then pop in a scope. And
now we can just use a selector. Awesome. So just to recap on the
syntax, here's a snippet without scoping, and here's a snippet with scoping. So
as I mentioned earlier, useGSAP uses a use effect or a
useLayoutEffect effect internally, so we can control when the effect should run by
passing in an array of dependencies. So if you don't pass in anything, it
defaults to an empty array. (Bye Brody) which runs the hook on the first
render. So we can add props to our dependency array to control when our
animation plays or reacts to state in some way. So here we're setting a
random value on click, and because we've added that prop into our dependency array,
when it changes, the hook's resynchronized with the new state. So the GSAP
code runs again and the box animates to the new value. So I wrote
this example with the dependency array. For simplicity. We can pass in just
an array as the second parameter, but we recommend passing in dependencies
through the config object. You just get more flexibility and it's easier to read.
And then we can use selectors again too. So now currently this box continues
on from its new value every time the prop changes. So this is the
default behaviour. If you define a dependency array and a dependency changes,
your GSAP objects, tweens, timelines, scroll triggers, et cetera, won't get
reverted. So they only get reverted when the component unmounts, not every time
that the hook is torn down. So we think this is going to be
the most commonly sought after behaviour, but it might not be what you're
after. So if you prefer the context to be reverted when any dependency changes
you can set revert on update. True in the let's take a little look
at this demo I've added revert on update. True to the green circle, I've
added a little animation delay as well. So we can see a little more
clearly. If we change the value by clicking on the button, the circle which
is reverted resets back to its original position in the DOm before each animation.
So you can kind of see it flip back to the centre. But the
blue square isn't reverted, so it continues on from its current animated
position. So when the useGSAP function executes, the context starts recording and
kind of stores any animations that were created during that run. So this lad
here is nice and safe. It's created as soon as the useGSAP function
runs. If we pass through the context so we have access to it, we
can log out what's inside. So if we log out the length of the
data array that's stored, you can see that there's one tween that's living in
the context at the moment. So when this context gets reverted, this tween
will too. So the main useGSAP function is considered context safe. Let's
pop another animation in here. But instead of it being created on load, we're
going to create it on click. So now, even though this tween is also
inside the useGSAP function, it's not actually created when the main useGSAP
function executes, it's created afterwards when someone clicks this button. So we
can see when we click the button and we log out the context. We've
still only got this one tween inside. So this one that we've added on
click hasn't been added to the context so it won't get cleared up when
the context is reverted. You might have also noticed that we're creating an event
listener here, but this isn't removed anywhere. So that's also going to stick
around in between component renders. Not good. So let's fix these issues and
create a nice context safe click animation. So in order for the animation
to be properly cleaned up, we need to scope its containing function to the
context. We can access the context safe function inside the main useGSAP function
through the second argument. So just like we passed in context, we're also going
to pass in context safe. So now we can create a context safe function.
Perfect. And then we're going to pop an animation inside here. So we want
to call this context safe function on a click event. So first let's make
it a named function and then we're going to call this context safe function
in an event listener, like so. So now that this is context safe, let's
log out the length of the context again here. So if we click the
button now, we can see that this animation has been added. So there's two
items now in the context. We've got the first tween that we added on
load, and then we've got the second tween that we added in this context
safe click function here. Perfect. So the last step here is to clean up
this event listener too. useGSAP returns, a cleanup function which you can use
for any additional tidying up. So let's return out and then we're going to
use this cleanup function to remove the event listener. Now, this way of writing
event listeners isn't super common in react. I think most people are writing
them out like this. So you can see that this function here is just
kind of floating around. It's very obviously not context safe. There's no
mention of usegsap or context safe anywhere, in fact. So how do we
sort this one out? Well, we can access context safe outside of the main
useGSAP function by using the returned object property. So let's create a usegsap
function here, and then we're going to do a little destructure to grab a
reference to the context safe function. And then we can write a context
safe function just like we did before, and we'll give it a name so
that we can call it directly from the click handler in our Jsx. So
we're using a ref here right now, but if we wanted to use a
class and have access to the scope, you can pass through a scope here.
And now we can safely use selectors in our GSAP code. So here's a
little before and after this click animation isn't safe, but this one's
created inside a nice context safe function, so it's safe and added to
the context. Thanks for watching, folks. We really hope this hook makes your
react and GSAP workflow super smooth and simple. Give it a try in your
projects and let us know what you think. We're always on hand in the
forums if you need a little nudge in the right direction. We've also written
a few guides over in our learning centre GSAP.com/react. We cover some
useful patterns and some more advanced animation and techniques, so definitely
check those out. Until next time, have fun and happy tweening.