Jump to content
Search Community

GSAP isActive function - React

chalatum test
Moderator Tag

Recommended Posts

Hello. I'm facing some issues with the GSAP isActive() function using React.

 

I made an aside navigation/menu panel. When  clicking on a button the navigation panel is deployed and its content follows (<ul/>, <li/>, etc.). For animating the navigation panel and its content I'm using a timeline in auseEffecthook like shown below. I want to use isActive() because I would like to prevent the user from spamming the toggle button. If the navigation toggle button is spammed by rapid clicks, the animation behave weirdly and the navigation content isn't displayed properly.

 

So I checked the doc here: https://greensock.com/docs/v2/TweenMax/isActive()

I tried to reproduce and it doesn't work. So I console logged tl.isActive() and it returns false all long the timeline run. I don't get it. Did I misunderstood something? I mean when the timeline is running it is supposed to return true, right? Can someone provides some help? Thanks.

 

 

useEffect(() => {

        const tl = gsap.timeline();

        const navRow1 = navRowRef.current;
        const navRow2 = navRow1.nextSibling;
        const navRow3 = navRow2.nextSibling;

        if (toggled === true) {

            tl.to(navigationRef.current, .9, {
                width: '100%',
                ease: 'power3.out'
            }).fromTo([navRow1.children[0], navRow2.children[0], navRow3.children[0]], {
                opacity: 0,
                x: -16
            }, {
                opacity: 1,
                x: 0,
                ease: 'power3.out',
                duration: .6
            }, "-=.45").fromTo([navRow1.children[1], navRow2.children[1], navRow3.children[1]], {
                opacity: 0,
                x: -22
            }, {
                opacity: 1,
                x: 0,
                ease: 'power3.out',
                duration: .6
            }, "-=.15").from(socialRef.current, .9, {
                opacity: 0,
                ease: 'power3.out'
            }, "-=.6");

            console.log(tl.isActive());

        } else {

            tl.to(innerNavRef.current, .45, {
                opacity: 0,
                ease: 'power3.out'
            }).to(navigationRef.current, .45, {
                width: '0%',
                ease: 'power3.out'
            });

        }

    }, [toggled]);

 

Link to comment
Share on other sites

Hey chalatum and welcome to the GreenSock forums.

 

1 hour ago, chalatum said:

If the navigation toggle button is spammed by rapid clicks, the animation behave weirdly and the navigation content isn't displayed properly.

That's because you're creating new tweens every single click and adding those to the timeline. We highly recommend that you create the animation outside of the click listener and just use control methods inside of the listener. Not doing so is one of the most common GSAP mistakes, as is adding tweens to timelines that have already been completed. I also write more about this concept in my article on animating efficiently.

 

I'd try doing something like this (psuedo-code, untested):

const tl = gsap.timeline({defaults: {ease: 'power3'}});

// Setup your animation
useEffect(() => {
  const navRow1 = navRowRef.current;
  const navRow2 = navRow1.nextSibling;
  const navRow3 = navRow2.nextSibling;
  
  // In animation
  tl.to(navigationRef.current, {
    width: '100%',
  }).fromTo([navRow1.children[0], navRow2.children[0], navRow3.children[0]], {
    duration: .9,
    opacity: 0,
    x: -16
  }, {
    opacity: 1,
    x: 0,
    duration: .6
  }, "-=.45").fromTo([navRow1.children[1], navRow2.children[1], navRow3.children[1]], {
    opacity: 0,
    x: -22
  }, {
    opacity: 1,
    x: 0,
    duration: .6
  }, "-=.15").from(socialRef.current, {
    duration: .9,
    opacity: 0,
  }, "-=.6");
  
  // Pause it
  tl.addPause();
  
  // Out animation
  tl.to(innerNavRef.current, {
    duration: .45,
    opacity: 0,
  }).to(navigationRef.current, {
    duration: .45,
    width: '0%',
  });
}, []);

// Control your animation on toggle
useEffect(() => {
  if(!tl.isActive()) {
    if (toggled === true) {
    	tl.play(0);
    } else {
        tl.play();
    }
  }
}, [toggled]);

Keep in mind that toggled should not be able to be changed unless the tl is not active according to this setup.

  • Like 1
Link to comment
Share on other sites

@ZachSaucier Thank you very much for your answer. I now understand a bit more about the logic.

 

1) This is almost working trying your solution. The only issue that remains is the fact that the code after the addPause() seems to be unreachable (?) because on toggled false the out animation does not trigger and the navigation panel isn't moving and stays static. I tried to solve this but did not manage to, I'm pretty new at GSAP.

 

2) Also React is complaining in the terminal about the fact that tl is not passed as a dependency to those useEffect() hooks. But it does not make sense to pass it (breaks the app at some point)... I always wondered if it is a big deal not to pass a variable as a dependency to useEffect() despite the fact that React warns you. What do you think?

 

Arthur

Link to comment
Share on other sites

Always use useRef if you want to access an animation elsewhere in your code.

 

const tl = useRef();

// Setup your animation
useEffect(() => {
  const navRow1 = navRowRef.current;
  const navRow2 = navRow1.nextSibling;
  const navRow3 = navRow2.nextSibling;
  
  // In animation
  tl.current = gsap.timeline({
    defaults: {ease: 'power3'}
  })
  .to(navigationRef.current, {
    width: '100%',
  }).fromTo([navRow1.children[0], navRow2.children[0], navRow3.children[0]], {
    duration: .9,
    opacity: 0,
    x: -16
  }, {
    opacity: 1,
    x: 0,
    duration: .6
  }, "-=.45").fromTo([navRow1.children[1], navRow2.children[1], navRow3.children[1]], {
    opacity: 0,
    x: -22
  }, {
    opacity: 1,
    x: 0,
    duration: .6
  }, "-=.15").from(socialRef.current, {
    duration: .9,
    opacity: 0,
  }, "-=.6");
  
  // Pause it
  tl.current.addPause();
  
  // Out animation
  tl.current.to(innerNavRef.current, {
    duration: .45,
    opacity: 0,
  }).to(navigationRef.current, {
    duration: .45,
    width: '0%',
  });
}, []);

// Control your animation on toggle
useEffect(() => {
  if(!tl.current.isActive()) {
    if (toggled === true) {
    	tl.current.play(0);
    } else {
        tl.current.play();
    }
  }
}, [toggled, tl]);

 

  • Like 2
Link to comment
Share on other sites

Hello @OSUblake. Thanks.  I gave a try with your code, but not on my navigation panel (will give a try on it tomorrow). Instead I tried it on small animations on nav/list items. I made a demo here: https://codesandbox.io/s/wizardly-shaw-9re8f?file=/src/ListItem.js

Animations behave a bit weirdly:

1) First I don't really get why the "link-background" in ListItem is showing when page just loaded. It is supposed to have a width of 0 and not appearing on first load.

2) When I rapidly hover nav/list items the animation get stuck and "link-background" is showing while it is supposed to have disappear with a width of 0. Is my strategy ok to make this animation working fine?

 

 

Link to comment
Share on other sites

12 hours ago, OSUblake said:

What you originally posted should work. Maybe try setting overwrite to "auto" for your animations.

Unfortunately it's not working very well. What do you mean by setting overwrite to "auto"?

I tried some stuff in the code sand box today but did not manage to find a solution. When I hover to fast on a nav item, the timeline get stuck in its first part and does not reach the second part. If I get ride of the addPause() the whole timeline runs, I don't want that.

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