Jump to content
Search Community

useGSAP (React): Timeline not reversing

pechschwarz Gmbh test
Moderator Tag

Recommended Posts

Hey there!

I have created a timeline within the useGSAP hook (React / Next.js), which I want to play or reverse using a button. Unfortunately, only the "normal" playback works. 

 

export default function Home() {
    const [animation, setAnimation] = useState(false);

    useGSAP(() => {
        const timeline = gsap.timeline({ paused: true });
        timeline.to(".text", {
            fontSize: "50px",
        });

        if (animation) {
            timeline.play();
        } else {
            timeline.reverse();
        }
    }, [animation]);

    return (
        <div>
            <div className="text">text!</div>
            <button
              onClick={() => {
                setAnimation(!animation);
              }}
            >
              toggle animation
            </button>
        </div>
    );
}

 

Have a look (Codesandbox)!

Link to comment
Share on other sites

Hi @pechschwarz Gmbh and welcome to the GSAP Forums!

 

Thanks for being a GSAP Club member and supporting GSAP!

 

Actually for toggling a GSAP Tween/Timeline is better to store it on a ref and then use any method to toggle it:

const tl = useRef();

const toggleTimeline = () => {
  tl.current.reversed(!tl.current.reversed());
};

useGSAP(
  () => {
    const boxes = gsap.utils.toArray('.box');
    tl.current = gsap
      .timeline()
      .to(boxes[0], { x: 120, rotation: 360 })
      .to(boxes[1], { x: -120, rotation: -360 }, '<')
      .to(boxes[2], { y: -166 })
      .reverse();
  }
);

Here is a simple demo that shows how it works:

https://stackblitz.com/edit/gsap-react-basic-f48716?file=src%2FApp.js

 

Hopefully this helps.

Happy Tweening!

Link to comment
Share on other sites


Excuse me for hijacking.

I was giving it a go myself earlier  - but since I'm far from being an expert with regard to React, I wasn't sure whether to post or not.

Here's what I came up with:

https://codesandbox.io/p/devbox/usegsap-fork-9vd2cg?file=%2Fapp%2Fpage.tsx

So just a quick question @Rodrigo.

If you wanted the timeline to play/reverse specifically dependent on a state in React (because you might want to use that exact state to update something else on the page) would the approach I used be eligible, or do you see any problems using it like that off the top off your head?

From what I understand, logic wise it should be pretty much like what you have suggested above - just taking a small detour via the state in React instead of triggering depending on the timeline's .reversed() 'state' directly, right?

Edit:
I just realized;
Instead of the toggleTimeline function I could also just use a useEffect hook with the state as its dependency to toggle the timeline depending on the state - and in the onClick handler just set the state instead. That's probably more React-y; but I guess the question of the eligibility does still stand.

https://codesandbox.io/p/devbox/usegsap-fork-forked-98wjvx?file=%2Fapp%2Fpage.tsx

  • Like 1
Link to comment
Share on other sites

Hey Paul!

 

Well when it comes to react is better to react (pun not intended) to state changes in effect hooks. If you want to just toggle a single Tween/Timeline that's stored on a ref, a regular useEffect hook:

const container = useRef();
const tl = useRef();
const [play, setPlay] = useState(false);

useGSAP(
  () => {
    tl.current = gsap
      .timeline({ paused: true })
      .to('.box', { x: 200 })
      .to('.box', { rotation: 360 })
      .reverse();
  },
  {
    scope: container,
  }
);

useEffect(() => {
  tl.current.reversed(!play);
}, [play]);

Of course you can use a second useGSAP hook for this as well, it doesn't have to be a useEffect hook:

useGSAP(
  () => {
    tl.current.reversed(!play);
  },
  {
    dependencies: [play],
  }
);

https://stackblitz.com/edit/stackblitz-starters-jd2dee

 

Another option is to just pass the dependency to useGSAP and create individual Tweens/Timelines according to the state property value:

const container = useRef();
const [play, setPlay] = useState(false);

useGSAP(
  () => {
    if (!play) {
      gsap.to('.box', { x: 0, rotation: 0 });
    } else {
      gsap.to('.box', { x: 200, rotation: 360 });
    }
  },
  {
    scope: container,
    dependencies: [play],
  }
);

But that depends on the fact that you want to create a different Tween each time.

https://stackblitz.com/edit/stackblitz-starters-9q1yxz

 

Hopefully this clear things up. Let us know if you have other questions.

Happy Tweening!

  • Like 2
  • Thanks 1
Link to comment
Share on other sites

14 minutes ago, Rodrigo said:

Well when it comes to react is better to react (pun not intended) to state changes in effect hooks.


😅 

Yeah, I already realized that myself (see Edit in post above).

Thanks a bunch for the quick reply and the demo - much appreciated!

It's been some time since I last touched on React, and it appears I tend to forget about its patterns; so this will definitely come in handy as a reminder.
 

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