Jump to content
Search Community

Nextjs — gsap.context — How to chain animations in different components.

tomKnox test
Moderator Tag

Recommended Posts

Hi there.
Please see the code below.
I use context to grab the items in my intro component.
Once those animations are done I would like to animate my navigation component.

I am unsure how to do this, as the scope is a different component.
I could create a new context but I am unable to link the two timelines....

I could use classes. That works, but I wonder why everyone is talking about context and react.

Next up: I am a bit confused about .revert() is this required? All my intro does is show a background, logo, animates it and then set itself to display none.

Thanks for brushing up my rusty gsap skills.
 

const intro = useRef(null);
const navigation = useRef(null);
useLayoutEffect(() => {
  let ctx = gsap.context(() => {
    let tl = gsap.timeline({
      defaults: { ease: Power3.easeInOut },
      onComplete: function () {
        display: 'none';
      },
    });
    //various intro-cover animations
    tl.to('.intro-cover', { delay: 0.5, autoAlpha: 0 });
    tl.from('.navigation', { opacity: 0, delay: 1.34 }, 0.23);

  }, intro);



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


return (
  <main>
  <Intro intro={intro} />
	<div className="site-wrap">
  		<Navigation navigation={navigation} />
    //rest of site
    </div>
</main>
);

 

Link to comment
Share on other sites

Hi,

 

The revert method in context ensures that when the component is unmounted any GSAP Instance will be killed, so nothing keeps running in the background causing a memory leak. Also GSAP Context's revert method is a way to work around the double call in useEffect hooks React introduced since version 18 in Strict Mode as explained here:

We strongly advice for using GSAP Context and doing proper cleanup in your setups, regardless of how simple they are. We've seen countless (and I'm not exaggerating with this) threads in the forums that were solved solely by including GSAP Context and doing proper cleanup in the effects hooks.

 

The fact that the scope resides in a different component doesn't creates any impediments for GSAP Context scoping to do it's job. Keep in mind that scoping in this case is to reduce focus the selector in a particular element and not the entire document. There are a few ways around this but the simplest one is to wrap your component around an extra DOM element, give that one a ref and pass that ref as the scope:

const intro = useRef(null);
const introWrapper = useRef(null);
const navigation = useRef(null);
useLayoutEffect(() => {
  let ctx = gsap.context(() => {
    let tl = gsap.timeline({
      defaults: { ease: Power3.easeInOut },
      onComplete: function () {
        display: 'none';
      },
    });
    //various intro-cover animations
    tl.to('.intro-cover', { delay: 0.5, autoAlpha: 0 });
    tl.from('.navigation', { opacity: 0, delay: 1.34 }, 0.23);

  }, introWrapper);

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


return (
  <main>
  <div ref={introWrapper}>
    <Intro intro={intro} />
  </div>
	<div className="site-wrap">
  		<Navigation navigation={navigation} />
    //rest of site
    </div>
</main>
);

But I see that you are already creating a ref in your component, so I assume that you are using forwarding refs, which is another of the options you have for that. If you consider the fact that React renders components starting from the children and then moving up the component tree, is safe to assume that both the DOM elements will be rendered and the ref will actually be a DOM node by the time the effect hook runs.

 

Hopefully this clear things up. If you keep having issues or other questions, please create a minimal demo using one of our starter templates on Stackblitz:

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

 

Or directly create one on Stackblitz' dashboard:

https://stackblitz.com/?starters=creative

 

Happy Tweening!

Link to comment
Share on other sites

TThank you. This clears things up. Good example too. However, the introWrapper needs to be closed off after the site wrapper in order for it to work.

 

const intro = useRef(null);
const introWrapper = useRef(null);
const navigation = useRef(null);
useLayoutEffect(() => {
  let ctx = gsap.context(() => {
    let tl = gsap.timeline({
      defaults: { ease: Power3.easeInOut },
      onComplete: function () {
        display: 'none';
      },
    });
    //various intro-cover animations
    tl.to('.intro-cover', { delay: 0.5, autoAlpha: 0 });
    tl.from('.navigation', { opacity: 0, delay: 1.34 }, 0.23);

  }, introWrapper);

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


return (
  <main>
  <div ref={introWrapper}>
    <Intro intro={intro} />
 
	<div className="site-wrap">
  		<Navigation navigation={navigation} />
    //rest of site
    </div>
 </div>
</main>
);

 

Link to comment
Share on other sites

Hi,

 

Another option in order to set the scope to the Intro component is better to use just forwarding refs:

https://reactjs.org/docs/forwarding-refs.html#gatsby-focus-wrapper

 

Here you can see how that can be achieved with GSAP:

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

 

But if the current approach you have works as expected and doesn't create any issues, then just keep it. As @mvaneijgen says: "If it works, it works"

 

Happy Tweening!

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