Jump to content
Search Community

ScrollTrigger Position Issues After Route Change in React App

moostakimahamed
Moderator Tag

Recommended Posts

moostakimahamed
Posted
I use GSAP’s ScrollTrigger in my React app, and everything works perfectly in the local environment. However, after deploying to Vercel, I’ve encountered an issue with ScrollTrigger when switching routes.

Here’s the behavior:

  • When I navigate to a page, the ScrollTrigger positions (start and end markers) are not aligned with the actual content. For example, the start and end markers appear above the intended elements. (I noticed it in all my sections)
  • If I refresh the page, the ScrollTrigger recalculates correctly, and everything works perfectly.
  • Navigating to another route causes the same issue to arise until I refresh the page again.

I’ve also noticed that I’m using the Swiper component in two routes at the bottom of the page, reusing the same component. This seems to cause similar issues even in my development server. (I have properly used context for this component)

 

[Note: I have added lazy loading for components and don't have any lazy loading images]

const Home = lazy(() => import("@/pages/Home/Home"));


Here is a minimal useGsap code from my code: 

useGSAP(() => {
    const cards = gsap.utils.toArray(
      ".card"
    ) as HTMLElement[];
  
    cards.forEach((item, i) => {
      gsap.from(item, {
        y: 50,
        duration: 1,
        opacity: 0,
        delay: i * 0.1,
        ease: "power2.out",
        scrollTrigger: {
          trigger: item,
          start: "top 90%",
          toggleActions: "play none none none",
          markers: true,
        },
      });
    });
  }, []);

 

Any advice on how to ensure ScrollTrigger recalculates properly? And the best practices to follow when using GSAP with React or Next.js

GSAP Helper
Posted

Without a minimal demo, it's very difficult to troubleshoot; the issue could be caused by CSS, markup, a third party library, a 3rd party script, etc. Would you please provide a very simple CodePen or Stackblitz that illustrates the issue? 

 

Please don't include your whole project. Just some colored <div> elements and the GSAP code is best. See if you can recreate the issue with as few dependencies as possible. Start minimal and then incrementally add code bit by bit until it breaks. Usually people solve their own issues during this process! If not, at least we have a reduced test case which greatly increases your chances of getting a relevant answer.

 

See the Pen aYYOdN by GreenSock (@GreenSock) on CodePen.

that loads all the plugins. Just click "fork" at the bottom right and make your minimal demo

 

Using a framework/library like React, Vue, Next, etc.? 

CodePen isn't always ideal for these tools, so here are some Stackblitz starter templates that you can fork and import the gsap-trial NPM package for using any of the bonus plugins: 

 

Please share the StackBlitz link directly to the file in question (where you've put the GSAP code) so we don't need to hunt through all the files. 

 

Once we see an isolated demo, we'll do our best to jump in and help with your GSAP-specific questions. 

  • Like 1
mvaneijgen
Posted

Hi @moostakimahamed welcome to the forum!

 

You probably have lazy load images and have not set the dimensions on the images, so when the page loads the images are zero pixels high and then get loaded and take up the size they really are, which in turn pushes all the content down trowing of all the calculations ScrollTrigger did on page load. 

 

You either have to set image dimensions or wait for the images to fully load and then call ScrollTrigger.refresh() 

 

This is just a guess, if this doesn't solve your issue please provide a minimal demo, so that we can take a look at your setup in action. 

 

Hope it helps and happy tweening!  

  • Like 2
Posted

Hi,

 

We have these demos

 

https://stackblitz.com/edit/vitejs-vite-d73sck (React)

 

https://stackblitz.com/edit/stackblitz-starters-hskbf2 (Next App Router)

 

Finally this could be due to the fact that the images, even though they are not lazy loading as you already mentioned, might not be fully loaded when the ScrollTrigger instances are created, then your code works as expected after a page refresh because the images are cached and rendered immediately before the ScrollTrigger instances are created. What you can do is run the ScrollTrigger.refresh() method after all the images are loaded.

 

We have this in our Learning Center in order to get going with GSAP on React projects:

https://gsap.com/resources/React/

 

Also these collections on Stackblitz for React and Next:

https://stackblitz.com/@gsap-dev/collections/gsap-react-starters

 

https://stackblitz.com/@gsap-dev/collections/gsap-nextjs-starters

 

Hopefully this helps

Happy Tweening!

  • Like 1
moostakimahamed
Posted

Hi, @Rodrigo

 

I fixed the issue by adding onLoad={() => ScrollTrigger.refresh()} to all <img> tags to refresh ScrollTrigger.

 

I noticed you use it { scope: main } with every useGSAP hook. Is that the recommended practice for setting the scope in GSAP hooks, or is there a better approach?

 

Additionally, could you share any recommended mid-level project resources that effectively combine React/Next.js with GSAP? I would greatly appreciate it.

 
Posted
2 minutes ago, moostakimahamed said:

I fixed the issue by adding onLoad={() => ScrollTrigger.refresh()} to all <img> tags to refresh ScrollTrigger.

That sounds expensive, especially if you have a lot of images. If you have a fixed number of images in your app, it would be better to use the onLoad callback to just increase a counter stored in a useRef() and when the counter reaches the total number of images you can call ScrollTrigger.refresh() only once.

3 minutes ago, moostakimahamed said:

I noticed you use it { scope: main } with every useGSAP hook. Is that the recommended practice for setting the scope in GSAP hooks, or is there a better approach?

That is the recommended approach, like that you can scope your selectors to that particular element that could be the top level DOM node in your component, like that you won't get any selectors to be used outside your component.

 

4 minutes ago, moostakimahamed said:

Additionally, could you share any recommended mid-level project resources that effectively combine React/Next.js with GSAP? I would greatly appreciate it.

The React specific resources we have in our Learning Center. Regardless of the project size using GSAP and React boils down to use them correctly. You can use React the wrong way on a one page project or a large SaaS app. That is not really tied to the size of the project, just to good practices. Same with GSAP, your project could have two Tweens or tens of complex and long Timelines, but if you don't use the tool correctly, most likely you'll run into some issues.

 

Hopefully this clear things up.

Happy Tweening!

  • Like 1

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