Jump to content
Search Community

Multiple animations in a timeline not working with the new React useGSAP hook

TaiwoJazz test
Moderator Tag

Go to solution Solved by TaiwoJazz,

Recommended Posts

So i just started using the new useGSAP hook. Here is a simple code but i'm not sure why the `#nav ul a` is not working and any other animation that follows.

Note: Only the first tween, `#navbar ul` played

I would also appreciate an example of scrollTrigger with this new hook. Thanks.


 

import gsap from 'gsap';
import { useGSAP } from '@gsap/react';

const useLayoutAnimation = (scope) => {
  useGSAP(
    () => {
      gsap
        .timeline({ defaults: { opacity: 0, duration: 0.7 } })
        .from('#navbar', { ease: 'linear', autoAlpha: 0, duration: 0.5 })
        .from('#navbar ul', {
          y: 50,
          duration: 0.6,
          delay: 2,
        })
        .from('#navbar ul a', {
          scale: 0,
          stagger: 0.1,
          transformOrigin: '50% 50%',
          ease: 'back',
          duration: 0.5,
        });
    },
    { scope }
  );
};

export default useLayoutAnimation;
Link to comment
Share on other sites

Hi @TaiwoJazz please don't ping anyone on the forum in the hopes to get an answer sooner, we strive to help everyone on these forums within a appropriate time span, but seen that it is the weekend you might have to wait a bit longer.

 

You're using React, but you're not following any of the recommendations we've provided when working with React. We've written an extensive guide on how to structure things, so please read through them! https://gsap.com/resources/React, below a snippet of what is extra important. If that doesn't solve your issue please create a minimal demo of your setup and tell us what you've already tried. Here are our Stackblitz starter templates that you can fork with here a direct link to the React version (please read this article!)

 

 Proper animation 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.

In GSAP 3.11, we introduced a new gsap.context() feature that helps make animation cleanup a breeze. All you need to do is wrap your code in a context call. All GSAP animations and ScrollTriggers created within the function get collected up in that context so that you can easily revert() ALL of them at once.

Here's the structure:

// typically it's best to useLayoutEffect() instead of useEffect() to have React render the initial state properly from the very start.
useLayoutEffect(() => {
  let ctx = gsap.context(() => {
    // all your GSAP animation code here
  });
  return () => ctx.revert(); // <- cleanup!
}, []);

This pattern follows React's best practices, and one of the React team members chimed in here if you'd like more background.

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

Happy tweening!

  • Like 1
Link to comment
Share on other sites

Hi @TaiwoJazz,

 

As @mvaneijgen points, please don't ping users and also be understanding that you posted this thread on a Saturday, so a slower response time could happen during the weekend.

 

Without a demo is hard for us to see what the issue could be, the only problem I can see in your code is that you're not using the useGSAP hook properly. The scope is part of an object, so it has to be key: value. In your snippet you seem to only be passing the key and not the value:

// With a ref
const container = useRef();

useGSAP(() => {}, {
  scope: container
});

// With a text selector
useGSAP(() => {}, {
  scope: "#container"
});

Happy Tweening!

Link to comment
Share on other sites

@mvaneijgen Firstly, let me start by apologizing for the ping. Also, i completely forget it's weekend. Apologies for that as well.

Secondly, i understand how to use gsap and i have spent some times with the docs. The reason i'm not using all the useLayoutEffect, useEffect and gsapContext is because i think with the new useGSAP, i don't need all those hooks again.  I guess i was wrong about that.


@Rodrigo Thanks for pointing out the proper use of useGSAP, i will try that if it is doesn't work, i will revert back to useLayoutEffect and gsapContext.

The question i will like to clarify is that, what is useGSAP hook replacing since it introduction or what does it change. I will be happen if a like to useGSAP docs can be provided as i have search the docs i didn't see any thing on it.

Thanks.

Link to comment
Share on other sites

3 hours ago, TaiwoJazz said:

The question i will like to clarify is that, what is useGSAP hook replacing since it introduction or what does it change. I will be happen if a like to useGSAP docs can be provided as i have search the docs i didn't see any thing on it.

I think this question is answered on the NPM package and Github readme. Did you check that out? 

 

Benefits of the useGSAP() hook:

  • Automatically handles cleanup using gsap.context()
  • Implements useIsomorphicLayoutEffect() technique, preferring React's useLayoutEffect() but falling back to useEffect() if window isn't defined, making it safe to use in server-side rendering environments.
  • Optionally define a scope for selector text, making it safer/easier to write code that doesn't require you to create a useRef() for each and every element you want to animate.
  • Defaults to using an empty dependency Array in its simplest form, like useGSAP(() => {...}) It was common for developers to forget to include that on React's useLayoutEffect(() => {...}, []) which resulted in the code being executed on every component render.
  • Exposes convenient references to the context instance and the contextSafe() function as method parameters as well as object properties that get returned by the useGSAP() hook, so it's easier to set up standard React event handlers.

 OLD

import { useEffect, useLayoutEffect, useRef } from "react";
import gsap from "gsap";

// for server-side rendering apps, useEffect() must be used instead of useLayoutEffect()
const useIsomorphicLayoutEffect = (typeof window !== "undefined") ? useLayoutEffect : useEffect;
const container = useRef();
useIsomorphicLayoutEffect(() => {
    const ctx = gsap.context(() => {
	    // gsap code here...
        }, container); // <-- scope for selector text
    return () => ctx.revert(); // <-- cleanup
}, []); // <-- empty dependency Array so it doesn't get called on every render

 NEW

import { useRef } from "react";
import gsap from "gsap";
import { useGSAP } from "@gsap/react";

const container = useRef();
useGSAP(() => {
    // gsap code here...
}, { scope: container }); // <-- scope is for selector text (optional)

 

We haven't put this in the official docs yet because we're in the process of reworking those before we "officially" announce the hook. Check back in a week or so and you'll see lots of useGSAP() in the docs related to React. 

  • Like 2
Link to comment
Share on other sites

@GreenSock Thanks a lot for this detail explanation. This make so much sense.

Just one thing i will like to clarify about the useGSAP hook.

The code below works fine when the page initially loads, after i navigate to other pages, the animation work. But once i go back to a page i have previously visited, the animation doesn't play again. This is not something i like, i will like to animation to keep playing irrespective of how many times i navigate between pages.

I'm thinking this has to do with dependencies. I will appreciate more clarification on this.

 

 useGSAP(
    () => {
      gsap
        .timeline()
        .from('ul', {
          y: 50,
          duration: 0.6,
          delay: 1,
          opacity: 0,
        })
        .from('ul a', {
          scale: 0,
          stagger: 0.1,
          transformOrigin: '50% 50%',
          ease: 'back',
          duration: 0.5,
        });
    },
    { scope: container },
    { dependencies: [] }
  );

 

Link to comment
Share on other sites

First of all, you are not using the API correctly. There should be only one config object, you have two. There is no need to pass in an empty dependency array either since that is the default.

 

if you still need help, please provide a 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. 

  • Like 1
Link to comment
Share on other sites

Hi,

 

Indeed the code snippet you provided should look like this:
 

useGSAP(
  () => {
    gsap
      .timeline()
      .from('ul', {
      y: 50,
      duration: 0.6,
      delay: 1,
      opacity: 0,
    })
      .from('ul a', {
      scale: 0,
      stagger: 0.1,
      transformOrigin: '50% 50%',
      ease: 'back',
      duration: 0.5,
    });
  },
  {
    scope: container ,
    dependencies: []
  }
);

Hopefully this helps.

Happy Tweening!

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