Jump to content
Search Community

React- Page transition would mess up animation

FarhanSU test
Moderator Tag

Recommended Posts

Hello! I am running an React app (CRA) with GSAP. I am still fairly new to React so I dont know the ins and out of React. I have a question about refreshing/re-running gsap animation after coming back to a page. So for example, If i am on the homepage and go through the page the animations works perfectly. However, If i navigate to another page and then come back to the Homepage either through the back-button or just through nav link, all the animations are gone and pictures and text are gone. I have used tl.kill() which solved the animation marker/content carrying over to different pages problem (although I dont think tl.kill() is the right approach.) I have used tl.refresh and then tl.enabled inside my useEffects() hooks to reinitialize the animations but that didnt work either.

 

I have attached a code sandbox of a simplified version of my code to give you guys a better idea. I would really appreciate from you guys! Thank you in advance!

 

This is my codesandbox: https://codesandbox.io/s/page-transition-omgpq?file=/src/App.js

See the Pen App.js by s (@s) on CodePen

Link to comment
Share on other sites

Hi,

 

There is a lot going on on your code.

 

First you have not one but four useEffect calls using an empty array. Now I haven't seen that before and perhaps there is a reason for it. Anyway , if you want to make your code more modular you can split the logic you want to use in that hook into different functions and call those functions inside a single useEffect hook and you can create those functions with the useCallback method in order to memoize the functions so their are created only in the initial render. Although your main component doesn't have any state or props, so it won't re-render again, after the initial render. Also there is no need to create a history instance to pass to the <BrowserRouter> component.

 

Second, the GSAP is complaining about some elements it can't find:

GSAP target null not found. https://greensock.com
in Homepg (created by Router.Consumer) in Router.Consumer (created by Route) in Route (at App.js:37) in App (at src/index.js:12)

That is worth take a look at it.

 

Third, if you can reduce everything to a single useEffect call in your component, at the very end of it, return a function that kills every GSAP instance you have in order to avoid any issues.

useEffect(() => {
  /*
  	All your code
  */
  // Finally when you are done with code inside the hook
  // return this function that will cleanup everything
  return () => {
    // Inside this function kill/reset everything GSAP related
  };
}, []);

 

Finally, I haven't even started working with ScrollTrigger so I have no idea about the ins and outs of the plugin, certainly I can see that you know far more than I do :D:D:D), so I can't help you with that and React. Perhaps @OSUblake@elegantseagulls, @Ihatetomatoes can chime in with advice about that. Maybe your issue is more related with the specific plugin than React itself and I can't even tell 🤷‍♂️;), what I can advice you, is with this issues I see on your React code.

 

Happy Tweening!!!

  • Like 2
Link to comment
Share on other sites

Hi @FarhanSU,

 

Looking at this I'm seeing a few things. I, like Rodrigo, don't see a need for using 4 useEffects. I'd use one with a return statement to kill the ScrollTriggers and all Timelines. Another thing I saw is that you aren't setting an ID for your ScrollTriggers, so I'm not sure if those inherit the Tween's var as the id or not. I've found it best to kill the scroll trigger then the tween.

 

const tl = useRef();
cont elRef = useRef(null)

useEffect(() => {
  
  tl.current = gsap.timeline({
  	scrollTrigger: {
      id: 'st-id'
      ...
    }
  })
    .to(elRef.current, {...})
        
  return () => {
    if (ScrollTrigger.getById('st-id')) {
      ScrollTrigger.getById('st-id').kill();
    }
    
    tl.current.kill();
  };
}, []);

 

  • Like 3
Link to comment
Share on other sites

Thank you @elegantseagulls and @Rodrigo so much! I have tried that and it does kill the timeline, but navigating away and then coming back to the page does not re-enable the animation. I have updated my code sandbox with what you suggested. I am not sure if i have to do that return statement for all my timeline hooks, but I tested it out but that did not seem to work.

Is there a way where I can re-enable the animation after someone returns to a page (say the homepg)?

 

Thank you once again guys I really appreciate it.

Link to comment
Share on other sites

Hi @FarhanSU,

 

Looking at your sandbox again, and you've got a lot going on.

 

What I believe is happening is that your page transitions are interfering with ScrollTrigger. ScrollTrigger is being initialized when both the incoming and outgoing pages are live, so it cannot get the proper height of the page. One fix would be to call ScrollTrigger.update() at the end of your page transition. Or make sure that the outgoing page isn't affecting the height or the page with ScrollTriggers on it (via position: absolute, and set a transformY to it avoid a jump).

 

And (imo) you're still using way to many refs/useEffects. You may consider breaking these into separate components, or use a single dom element ref, and query selectors based on that.

Also, you're loading a few animation libraries (React Spring, Framer Motion (this looks maybe unused?), and GSAP). Why not use GSAP for everything? It seems like a lot of extra bloat to use Spring for page transitions and GSAP for on-page animations in this scenario.

  • Like 3
Link to comment
Share on other sites

Thank you @elegantseagulls! Apologies for the late response. I was trying somethings out with my codes. I am also looking at ways to do page transition using gsap but I haven't figured that out yet.

On 9/14/2020 at 2:24 PM, elegantseagulls said:

or use a single dom element ref, and query selectors based on that.

Would you also explain what you mean by this? I thought you needed to use a ref for each element you want to target so it can only run once. Do you mean using one useffects and placing all the different scrolltrigger elements in it?

I also found a work around with the animation problem. I updated my codesandbox and it is on line 12-19. The question I have about this is how can I optimize that to be more efficient?

 

Thank you for all your help and patience!

Link to comment
Share on other sites

Hi @FarhanSU,

 

The useEffects you have don't have any way to know which element they are referencing, so there may be issues with them acting up. I think for your use case, using useCallback May be better:
 

const TL = useRef();
const myRef = useCallback((node) => {
	if (!node) return; // check if ref (node) is rendered

	const childEl = node.querySelector('.child-el'); 
    
	TL.current = gsap.timeline()
      .to(node, { autoAlpha: 1 })
      .to(childEl, { x: 55 })
},[])

useEffect(() => () => {
  // all garbage cleanup all goes in a single useEffect for when component leaves
  if (TL.current) {
  	TL.current.kill();
  }
});

return() {
  <div ref={myRef} />
}

 

Also for Transitions, you may consider React's own React Transition Group (https://reactcommunity.org/react-transition-group/). This is what we use for most of our page/component transitions with GSAP or CSS transitions. There may be a few tricks you may need to do with CSS/state for managing page scroll location, very much depending on your setup, but that's a more in-depth deep-dive.

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