Jump to content
GreenSock

ericnguyen23

Creating GSAP Timeline with React Project

Warning: Please note

This thread was started before GSAP 3 was released. Some information, especially the syntax, may be out of date for GSAP 3. Please see the GSAP 3 migration guide and release notes for more information about how to update the code to GSAP 3's syntax. 

Recommended Posts

Question (for those familiar w/ React and GSAP) regarding setting Timeline with functional components.

 

I'm aware that to access DOM, I would have to reference and set animation like so, which works just fine:

// creating state objects
const [animation, setAnimation] = useState();

// Set variable using useRef for functional component
let headingRef = useRef(null);

// add reference to the DOM element
<h1 ref={element => {headingRef = element;}}>Hello</h1>  

/ // animate using useEffect hook and setAnimation 
useEffect(() => {
    setAnimation(
      TweenMax.to(headingRef, 1, {
        css: {
          height: 120,
        },
      })
    );
}, []);

 

Now, what if I wanted to create a timeline. Do I just set it like so:

let tl = new TimelineMax();

Or do I need to store it in a state object?

Link to comment
Share on other sites

Hi,

 

As mentioned before I haven't had time to dig deeply into the Hooks API and all I can offer right now is a simple example but no real explanation on how it actually works, sorry about that.

 

Here is a live sample using a Timeline instance with React hooks:

 

https://stackblitz.com/edit/gsap-react-hooks-timeline-instance-toggle

 

As you can see it uses a useEffect at first run in order to create the timeline and then you can add all the child instances you want to the timeline.

 

Unfortunately this doesn't works:

 

let tweenTarget = null;
const tl = new TimelineLite({paused: true});

useEffect(() => {
  tl
    .to(tweenTarget, 0.5, {x: 100})
    .to(tweenTarget, 0.5, {y: 100})
    .to(tweenTarget, 1, {rotation: 360})
    .reverse();
}, []);

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

Even though in the useEffect callback triggered by the toggle update, tl is defined and it's reversed state is updated, nothing happens. This is the part I can't give you a proper explanation about.

 

For the foreseeable future just work with the timeline in the initial useState and then in the useEffect add the instances, like in the live sample. As soon as I have an official explanation about this, I'll post it here and in the other threads dealing with hooks.

 

Happy Tweening!!!

  • Like 6
Link to comment
Share on other sites

Thanks @Rodrigo This helps. 

 

I'll set my timeline up like this now:

const [tl] = useState(new TimelineMax());

 

  • Like 1
Link to comment
Share on other sites

6 hours ago, Rodrigo said:

Unfortunately this doesn't works:

 


let tweenTarget = null;
const tl = new TimelineLite({paused: true});

useEffect(() => {
  tl
    .to(tweenTarget, 0.5, {x: 100})
    .to(tweenTarget, 0.5, {y: 100})
    .to(tweenTarget, 1, {rotation: 360})
    .reverse();
}, []);

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

 

The animation will run if you comment out the tl in the second useEffect, which doesn't make a lot sense.

 

See the Pen 38b42207b0a9b5c0514ccc0508da9862 by osublake (@osublake) on CodePen

 

And like you, I haven't dug into the hooks API yet, so maybe I'm missing something obvious. 

 

  • Like 2
Link to comment
Share on other sites

  • 1 month later...
On 8/15/2019 at 7:15 PM, ericnguyen23 said:

I'll set my timeline up like this now:


const [tl] = useState(new TimelineMax());

 

 

That creates a new timeline on every render, which is wasteful, and could cause performance problems.

 

And doing it this way creates an error because the second useEffect can't access the timeline until the next render.

 

const [tl, setTl] = useState();
  
useEffect(() => {
  setTl(
    new TimelineMax()
      .to(tweenTarget, 0.5, {x: 100})
      .to(tweenTarget, 0.5, {y: 100})
      .to(tweenTarget, 1, {rotation: 360})
  );
}, []);

useEffect(() => {    
  tl.reversed(!toggle); // error on first render
}, [toggle]);

 

This approach seems to be much better.

 

const tl = useRef();
  
useEffect(() => {        
  tl.current = new TimelineMax()
    .to(tweenTarget, 0.5, {x: 100})
    .to(tweenTarget, 0.5, {y: 100})
    .to(tweenTarget, 1, {rotation: 360});
}, []);

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

 

 

Related post:

 

 

  • Like 3
Link to comment
Share on other sites

  • 1 month later...

When I try to use a ref like this:

const tl = useRef();

tl.current.to(...) // This would be in an effect that runs once on mount

I get this error:

Uncaught TypeError: Cannot add property _gsap, object is not extensible
    at new GSCache (gsap-core.js:1502)
    at _harness (gsap-core.js:122)
    at new Tween (gsap-core.js:2983)
    at Object.to (gsap-core.js:3325)
    at goToAndAnimate (StatusIcon.tsx:62)
    at StatusIcon.tsx:43
    at commitHookEffectList (react-dom.development.js:21997)
    at commitPassiveHookEffects (react-dom.development.js:22031)
    at HTMLUnknownElement.callCallback (react-dom.development.js:336)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:385)

The line that seems to be triggering this is:

let currentTime = tl.current.time()

 

Things just work when I put it in a state rather than a ref (although then the timeline seems to get really wonky).

 

Any idea why this might be happening?

Link to comment
Share on other sites

Just now, OSUblake said:

I don't know why the success isn't working though.

 

Oh, you need to use tl.current here.

 

gsap.to(tl.current, {
        duration: 0.3, 
        time: labelTime, 
        ease: "none", 
        onComplete: () => {
          tl.current.resume()
        }
      });

 

  • Like 4
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.
×