Jump to content
Search Community

Invalid scope on dynamically rendered elements with scrolltriggers when switching routes in Next js

aijololo test
Moderator Tag

Go to solution Solved by Rodrigo,

Recommended Posts

Hello,

I was not able to recreate this issue in codesandbox or stackblitz, but hope you can give some insight based on what I can provide here.

 

I have a Next.js website using the pages router, and I have an issue with a component that has elements rendered dynamically from a script after the component mounts. (It's a social media feed from Curator.io)
The posts in the feed have a scrolltrigger applied to them after the feed has loaded.

const curatorContainer = useRef()

useGSAP(() => {
    if ( feedLoaded ) {
	ScrollTrigger.create({
        trigger: curatorContainer.current,
        start: "top bottom-=200px",
        onEnter: () => {
          gsap.fromTo('.crt-post-c', 
          {
            opacity: 0
          },
          {
            opacity: 1,
            duration: 0.75,
            delay: 0.2,
            stagger: 0.1,
            overwrite: 'auto'
          })
        },
        onLeaveBack: () => {
          gsap.to('.crt-post-c', {
            opacity: 0,
            duration: 0.5,
            overwrite: 'auto'
          })
        },
      })
    }
  }, { scope: curatorContainer, dependencies: [feedLoaded] })

return (
  <div ref={curatorContainer}>
  ...
  </div>
)

 

On the first load everything works fine, but if I navigate to another page and back to the page with this component, I get several "Invalid scope" errors in the console (some on a gsap timeline unrelated to the component that seems to cause the errors). I also get the error "GSAP target .crt-post-c not found." even tho this code spicifically checks for any existing .crt-post-c before running.

 

However the animations work without issues, so I just want to know what's causing the errors and if I can get rid of them.

 

There is no errors when using this same gsap implementation on things that aren't dynamically rendered.

Link to comment
Share on other sites

Hi,

 

There is not a lot we can do without a minimal demo, but from what you describe the only guess I can make is that feedLoaded  (whatever that is, a boolean, array, etc.) is not falsy when you navigate back to that route 

22 hours ago, aijololo said:

even tho this code spicifically checks for any existing .crt-post-c before running.

I don't see that in the code snippet you posted

 

22 hours ago, aijololo said:

There is no errors when using this same gsap implementation on things that aren't dynamically rendered.

Clearly there is something related with the way you're handling this side of your app, that is causing this problem, unfortunately without a minimal demo there is not a lot we can do. We have a collection of NextJS starter templates that you can fork:

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

 

Happy Tweening!

Link to comment
Share on other sites

  • Solution

Yeah the issue could be that the fact that the boolean on your state is updated that doesn't necessarily means that the elements are rendered yet, especially when you run that ScrollTrigger.refresh() method. Any particular reason for that? I don't really see any reason for having that code in that component. Removing that single line seems to fix the issue.

 

As far as I can tell there is no real need to have that refresh call there, since when that component is unmounted the useGSAP hook will revert everything inside of it, so there shouldn't be any reason to globally refresh ScrollTrigger, unless there are other ScrollTrigger instances in your parent component, but still 

if you need it you can add the revertOnUpdate option to the useGSAP hook to revert everything:

useGSAP(
  () => {
    if (feedLoaded) {
      ScrollTrigger.refresh();
      // rest of your code
    }
  },
  {
    scope: curatorContainer,
    revertOnUpdate: true,
    dependencies: [feedLoaded],
  }
);

Hopefully this helps.

Happy Tweening!

 

  • Thanks 1
Link to comment
Share on other sites

Thank you, the revertOnUpdate seems to fix the issue.

Can't say I understand why this works tho, as the useGSAP is reverted when the component is unmounted?

 

The Refresh is because I have ScrollTriggers on elements below the feed that don't work without it. And removing the Refresh doesn't fix the issue in my full project.

 

Another thing I tested is adding tweens without ScrollTriggers to the feed, and that doesn't cause any errors.

Link to comment
Share on other sites

6 hours ago, aijololo said:

Can't say I understand why this works tho, as the useGSAP is reverted when the component is unmounted?

But when the dependency is updated, the entire hook runs again and you have some lingering GSAP instances that are pointing to an element that is not rendered yet because of the useEffect/useLayoutEffect double call React does on Strict Mode. The useGSAP hook will revert only in the initial call of the hook but not when the dependencies are updated, why? Because we wanted to give users the opportunity to put all their logic in the useGSAP hook instead of creating a useGSAP and a useEffect hook, but not every time you need to re-run some logic because of a state/prop change you need to revert and re-create your GSAP instances, enter revertOnUpdate. With that useGSAP will not only run your logic inside the hook on a state/prop update but also revert and re-create your GSAP instances.

 

Hopefully this clear things up.

Happy Tweening!

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