Jump to content
Search Community

How to make animations in different useEffects share the same timeline?

Ishan Shishodiya test
Moderator Tag

Recommended Posts

I have a useEffect hook which does some animations which goes like this -

useEffect(() => {
    const ctx = gsap.context(() => {
      const tl = gsap.timeline();
      tl.from(".hero-text", {
        opacity: 0,
        x: "-5vmin",
        delay: 1,
        duration: 1,
        ease: "expo.out",
        stagger: 1,
      });

      tl.to(
        ".hero-text",
        {
          letterSpacing: "0.1em",
          stagger: 0.9,
        },
        "-=2.5"
      );
    });

    return () => ctx.revert();
  }, []);

I have another animation that I want to run after this animation has ended, but if I add it inside the same useEffect hook it'll make the code a bit messy. I can definitely have a completely different useEffect hook and write the animation there but that way I won't be able to use the timeline defined for this animation. Currently I am just using a delay but I feel like that ain't the best way of achieving the result I want.

 

Is there a way I can add an animation to the same timeline while making sure that the code ain't really messy. Can contexts help in this? Having the animations inside useEffect ain't necessary for my purpose so am open to any sort of suggestions that can be implemented in React, or specifically NextJS.

Link to comment
Share on other sites

I found a method to do this and it involves creating a mater timeline tland then adding child timelines to this for every animation. To keep the code organized I make functions for each timeline in which I do something like this -

const heroAnimation = () => {
    const heroTl = gsap.timeline({ delay: 1 });
    heroTl.from(".hero-text", {<animation params>});
    heroTl.to(".hero-text", {<animation params>}, "-=2.5");
    tl.add(heroTl);
  };

I do this for every animation I want to create and then at the end add them all to one useEffect-

useEffect(() => {
  tl.set(pageRef.current, { visibility: "visible" });
  heroAnimation();
  scrollGuideAnimation();
}, []);

The result does seem to work the way I expected it to. I'd still love some suggestions though.

Link to comment
Share on other sites

Hi,

 

Is this thread related to the comment you posted in this thread?

If so please let us know so we can delete that particular comment and focus our attention solely on this thread.

 

If possible please create a minimal demo that we can take a look at in order to get a better idea of what the issue could be. You can fork one of our starter templates in order get started:

https://stackblitz.com/@GreenSockLearning/collections/gsap-react-starters

 

Finally you could take a look at this resource from our Advanced GSAP + React article:

https://greensock.com/react-advanced#communication

 

If you only want to split your animations into different functions in order to keep your useEffect hook smaller and your code easier to read I would recommend you to keep using GSAP Context in your effect hook in order to avoid double calls on Strict Mode:

const createHero = () => {
  const tl = gsap.timeline();
  /* Add instances to your timeline */
  return tl;
};

const createAnother = () => {
  const tl = gsap.timeline();
  /* Add instances to your timeline */
  return tl;
};

useLayoutEffect(() => {
  const ctx = gsap.context(() => {
    const mainTl = gsap.timeline();
    const heroTl = createHero();
    mainTl.add(heroTl);
    const anotherTl = createAnother();
    mainTl.add(anotherTl);
  });
  return () => ctx.revert();
}, []);

Like that GSAP Context will be aware and do proper cleanup on every GSAP Instance you create in your component.

 

Hopefully this helps.

Happy Tweening!

Link to comment
Share on other sites

@Rodrigo I won't say that those two are completely related as the comment is a Redux Toolkit issue but yeah both originated from the same issue of wanting to share one master timeline across multiple components. In the code I have working right now I have done something similar to the example you gave and it works as I wanted it to. You can view it in this codesandbox.

 

I used prop drilling to pass down the master timeline to the children component as Cassie's article suggested and then just did something like this to add the timeline to the master timeline as shown in Cassie's example codepen in their article -

const FirstSection = ({ tl }: Props) => {
  useEffect(() => {
    if (tl) {
      const hero = gsap.timeline({ delay: 1 });
      hero.from(".hero-text", {});
      tl.add(hero);
    }
  }, [tl]);

  return <JSX code>
};

Then I just call these components in the main parent component and the sub-timelines like hero timelines get added in the sequence get added to the master timeline in the parent.

 

The prop drilling method works nice when we don't have to drill the prop too many times, but I was wondering if I could store the master timeline as a global state and then call it in all these children. I tried doing it using RTK where I created a timeline slice and stored gsap.timeline as the initial state but ran into the error of "Too many recursion". That post I made there is more of an RTK and GSAP so I think that that post and this post are two different things.

Link to comment
Share on other sites

Hi,

 

I created an example for sharing a Timeline between components using Redux Toolkit:

https://stackblitz.com/edit/vitejs-vite-bkoybk?file=src%2FApp.jsx&terminal=dev

 

I didn't ran into any recursive errors, I do get an error about a non-serializable value being passed around. I tried to add the specific action to the ignoredActions array using Redux Middleware but it didn't work 🤷‍♂️. Maybe I'm missing something here.

 

IMHO this is extremely convoluted for sharing a reference to a GSAP Instance, I'd use React Context and even further I'd use Vue or Svelte. I know by experience that using Vue with either VueX or Pinia in this scenario is far simpler than this, but I understand that sometimes the tools being used in an app are not the call of a single developer.

 

Hopefully this helps.

Happy Tweening!

  • Like 2
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...