Jump to content
Search Community

generic performance issue with timeline in React

David12345 test
Moderator Tag

Recommended Posts

Hi!

 

I have a timeline that is executed when a boolean is set to true. It's not particularly heavy but it does change x, width, height for a given div. When the boolean is set to false, then another timeline runs that basically reverses the changes on the same div, but to another x coordinate, that's why I needed to create a new "returning" timeline. The boolean change is detected with useLayoutEffect.

After each run the timelines start to become more and more laggy, dropping more and more frames when they are executed. I tried to optimize performance, like .kill before the timeline would run. I also tried .clear() but none of these things seem to help on the performance issue.

 

Do you have any ideas why I might have this behavior?

 

Thank you for your attention in advance.

Link to comment
Share on other sites

https://codesandbox.io/s/lucid-leftpad-s12cb?file=/src/App.js

This example is very similar in nature (how the animation is initialized and then reversed; not sure that it's a good practice though, how I do it with useLayoutEffect/useEffect - if you have some recommendations I'd appreciate it).

 

However, getting to the point: I'm not able to reproduce the slowing down. Basically, what happens in my app is that with each play and reverse more and more frames are dropped leading to decreasing performance feeling.

Link to comment
Share on other sites

It might be better to create your animation once, and then reverse it.

 

See the Pen eYWGeGe by GreenSock (@GreenSock) on CodePen

 

55 minutes ago, David12345 said:

However, getting to the point: I'm not able to reproduce the slowing down. Basically, what happens in my app is that with each play and reverse more and more frames are dropped leading to decreasing performance feeling.

 

Sounds like you might adding animations to an already existing timeline, making it longer and longer, but it's hard to say without seeing code that can reproduce the issue. Are you doing something like this?

 

// bad
const myTimeline = gsap.timeline();

useLayoutEffect(() => {
    if (play) {
      // bad
      myTimeline.to(boxRef.current, {
        backgroundColor: "yellow",
        width: 300, 
        height: 300, 
        x: 150, 
        rotation: 160
      });
    }

    if (!play && alreadyRan) {
      // bad
      myTimeline.to(boxRef.current, {
        backgroundColor: "blue",
        width: "30",
        height: "30",
        x: "10",
        rotation: "-=220"
      });
    }
  }, [play, alreadyRan]);

 

And make sure you don't have any CSS transitions on properties you are animating.

 

Also, be sure to check out our React Guide.

 

  • Like 2
Link to comment
Share on other sites

Right. It seems like that I'm adding more and more to the timeline. 

However, before actually starting the timeline I use .kill, .invalidate in order to clear it. Shouldn't that be enough to clear the timeline? Is there any other way to completely dismount the timeline on each run?

 

I do not think the reverse is good for me, because the x position when I reverse is different than the original play x value. Or is there another way to set the x value for the reverse run differently?

Link to comment
Share on other sites

It's hard to advice without seeing some code. Notice how I pointed out what is bad. Are you doing that? You should never create a timeline outside of a hook.

 

// A really, Really bad idea
const myTimeline = gsap.timeline();

useLayoutEffect(() => {
   ...
}, [play, alreadyRan]);

 

And did you check out React Guides?

 

 

 

  • Like 1
Link to comment
Share on other sites

1 hour ago, David12345 said:

However, before actually starting the timeline I use .kill, .invalidate in order to clear it. Shouldn't that be enough to clear the timeline? Is there any other way to completely dismount the timeline on each run?

 

We would need to see exactly how you are creating your timelines, and calling kill.

 

  • Like 1
Link to comment
Share on other sites

If you need to access your timeline outside a hook, do it like this:

const tl = useRef();

useLayoutEffect(() => {
  tl.current = gsap.timeline();  
  ...
  
  return () => tl.current.kill()  
}, [play, alreadyRan]);

 

Otherwise:

useLayoutEffect(() => {
  const tl = gsap.timeline();
  ...
  
  return () => tl.kill()  
}, [play, alreadyRan]);

 

  • Like 1
Link to comment
Share on other sites

Thank you. These are great sources and I learned a lot from these. While checking these I also uncovered the source of error! It was unrelated to GSAP. It was a requestAnimationFrame that, upon useLayoutEffect callbacks got restarted every time, but the old one did not get cleared. This caused that by each run, the performance kept decreasing since the more and more running instances of requestAnimationFrame took the computing resources!

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