Jump to content
Search Community

ScrollTrigger Timeline Animation and React State Changes

Loust test
Moderator Tag

Go to solution Solved by GreenSock,

Recommended Posts

Hello community. So, after numerous searches and head-banging, I can't find the solution. I have an animation triggered by ScrollTrigger. This animation targets phrases. These phrases are inserted into the DOM through a map, triggered either on rendering or when the state changes. The desired effect is that the state, which is an array of strings, changes when the user hovers over one of the icons next to these phrases. Depending on the targeted icon, there can be two, three, or four phrases. The problem is that during onLeave, onEnterBack, or onLeaveBack, only the number of phrases from the first targeted icon is animated. In short, the initial state contains four phrases; if I then hover over an icon containing 3 phrases, then another icon with 2, then one with 3, then one with 4, only 3 phrases are animated in the ScrollTrigger animation. If the sequence is 4 phrases initially, then 2 on hovering over an icon, then 3, then 4, only 2 phrases are animated. I specify that I also use Locomotive Scroll, and due to the ScrollTrigger proxy, I cannot use useEffect with a dependency array in my .js function.

Link to comment
Share on other sites

Without a minimal demo, it's very difficult to troubleshoot; the issue could be caused by CSS, markup, a third party library, a 3rd party script, etc. Would you please provide a very simple CodePen or Stackblitz that illustrates the issue? 

 

Please don't include your whole project. Just some colored <div> elements and the GSAP code is best. See if you can recreate the issue with as few dependancies as possible. Start minimal and then incrementally add code bit by bit until it breaks. Usually people solve their own issues during this process! If not, at least we have a reduced test case which greatly increases your chances of getting a relevant answer.

 

See the Pen aYYOdN by GreenSock (@GreenSock) on CodePen

that loads all the plugins. Just click "fork" at the bottom right and make your minimal demo

 

Using a framework/library like React, Vue, Next, etc.? 

CodePen isn't always ideal for these tools, so here are some Stackblitz starter templates that you can fork and import the gsap-trial NPM package for using any of the bonus plugins: 

 

Please share the StackBlitz link directly to the file in question (where you've put the GSAP code) so we don't need to hunt through all the files. 

 

Once we see an isolated demo, we'll do our best to jump in and help with your GSAP-specific questions. 

Link to comment
Share on other sites

Hi,

 

Based on your description ScrollTrigger Batch seems to be the right tool for this scenario:

https://gsap.com/docs/v3/Plugins/ScrollTrigger/static.batch()

 

Also proper cleanup is very important with frameworks, but especially with React. React 18 runs in strict mode locally by default which causes your useEffect() and useLayoutEffect() to get called TWICE.

 

Since GSAP 3.12, we have the useGSAP() hook (the NPM package is here) that simplifies creating and cleaning up animations in React (including Next, Remix, etc). It's a drop-in replacement for useEffect()/useLayoutEffect(). All the GSAP-related objects (animations, ScrollTriggers, etc.) created while the function executes get collected and then reverted when the hook gets torn down.

 

Here is how it works:

const container = useRef(); // the root level element of your component (for scoping selector text which is optional)

useGSAP(() => {
  // gsap code here...
}, { dependencies: [endX], scope: container }); // config object offers maximum flexibility

Or if you prefer, you can use the same method signature as useEffect():

useGSAP(() => {
  // gsap code here...
}, [endX]); // simple dependency Array setup like useEffect()

This pattern follows React's best practices.

 

We strongly recommend reading the React guide we've put together at https://gsap.com/resources/React/

 

If you still need help, here's a React starter template that you can fork to create a minimal demo illustrating whatever issue you're running into. Post a link to your fork back here and we'd be happy to take a peek and answer any GSAP-related questions you have. Just use simple colored <div> elements in your demo; no need to recreate your whole project with client artwork, etc. The simpler the better. 

 

Happy Tweening!

Link to comment
Share on other sites

Thank you for your responses and their speed. So, yes, I had previously tested useGSAP without success. I was completely unfamiliar with Batch, it's really good, but it creates a very erratic behavior after the state change. Currently, I'm trying to create a minimal demo with React, but as soon as I try to go to CodePen, it asks me to log in, and I'm not sure where I put my password. I'm waiting to have it sent to me, otherwise I'll quickly create another account. 

 

Link to comment
Share on other sites

In fact, the scrollTrigger works very well. However, once I hover over one of the buttons, only their sentences are taken into account from a set of potentially larger number of sentences.

 

Link to comment
Share on other sites

  • Solution

I noticed several issues: 

  1. You're not doing proper cleanup. Every time you change the text, you're creating an entirely new animation and ScrollTrigger, and all the old ones are sticking around. So you end up with more and more and more that are all trying to operate on the same elements. 
  2. It looks like you're using a setTimeout() to work around the fact that React doesn't immediately apply the changes when you setText(). If you're trying to run an animation when that text changes, you should do it the proper way in React which is to set up an effect with that text as a dependency (this is totally unrelated to GSAP, FYI). 
  3. You appear to be hard-coding onEnter/EnterBack/onLeaveBack callbacks on your ScrollTrigger to do exactly what you can do more easily with toggleActions. 
    // old
    onLeave: () => tl.reverse(),
    onEnterBack: () => tl.play(),
    onLeaveBack: () => tl.reverse()
    
    // new
    toggleActions: "none reverse play reverse"

     

  4. There seem to be logic issues - I don't really understand what you're expecting to happen.

Here's my best guess at what you're trying to do: 

https://stackblitz.com/edit/stackblitz-starters-8ab6xd?description=React TypeScript starter project&file=src%2FApp.tsx&title=React Starter

  • Like 1
Link to comment
Share on other sites

Indeed, I didn't think of that approach. I searched for many things, yet in vain. Thanks for your help. One question; so now, we prefer to use toggleActions? Are onEnter, onEnterBack, etc., deprecated? I'm new to the game, actually. I've been using GSAP for about a week, and React for a few months. Otherwise, I'll look on the internet to find out about toggleAction. Thanks again, anyway ;), your solution is very clean.

Link to comment
Share on other sites

25 minutes ago, Loust said:

One question; so now, we prefer to use toggleActions? Are onEnter, onEnterBack, etc., deprecated?

No, not at all. We made ScrollTrigger to be super flexible. toggleActions aren't new at all - they were in the original release. onEnter/onLeave/onEnterBack/onLeaveBack are simply callbacks that allow you to do ANYTHING at those points. The toggleActions are just a shortcut way to control the associated animation. 

 

Have fun!

Link to comment
Share on other sites

I understand completely. `onEnter/onLeave/onEnterBack/onLeaveBack` allows associating functions that are not necessarily correlated with the triggering animation. A brilliant approach. Truly impeccable what you've done. I wholeheartedly recommend. Thanks once again to you and your responsive community space. One last question, if I may, don't bother otherwise, I'll do my research and tests, but does `ScrollTrigger.create()` auto-destruct like itself, kind of one-time use?

 

Link to comment
Share on other sites

6 minutes ago, Loust said:

One last question, if I may, don't bother otherwise, I'll do my research and tests, but does `ScrollTrigger.create()` auto-destruct like itself, kind of one-time use?

I don't understand the question. When/How would you expect it to "auto-destruct"? Maybe it would help if you explain the "why" behind your question.  Perhaps you were asking if ScrollTriggers created while the useGSAP() function executes will automatically revert and destroy themselves when the hook gets torn down? If so, the answer is "yes". 🙂

 

8 minutes ago, Loust said:

A brilliant approach. Truly impeccable what you've done. I wholeheartedly recommend. Thanks once again to you and your responsive community space.

💚

Link to comment
Share on other sites

2 hours ago, GreenSock said:

Je ne comprends pas la question. Quand/Comment vous attendez-vous à ce qu'il « s'autodétruise » ? Il serait peut-être utile que vous expliquiez le « pourquoi » derrière votre question. Peut-être demandiez-vous si les ScrollTriggers créés pendant l' exécution de la fonction useGSAP() reviendraient automatiquement et se détruiraient lorsque le hook serait détruit ? Si tel est le cas, la réponse est « oui ». 🙂

Yes, that's exactly what I was referring to, to avoid memory leaks and the kind of behavior I encountered with my bad practice using a simple ScrollTrigger. Thanks, Cassie, for your video; I'll watch it tomorrow.

  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...