EASY React Animation with useGSAP()

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
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.
Info
Channel: GreenSockLearning
Views: 54,509
Rating: undefined out of 5
Keywords: react, gsap, animation, greensock, usegsap
Id: l0aI8Ecumy8
Channel Id: undefined
Length: 12min 44sec (764 seconds)
Published: Tue Jan 23 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.