Jump to content
Search Community

Next.js / GSAP, Scrolltrigger: Cannot read properties of undefined (reading 'end')

Authentiq test
Moderator Tag

Go to solution Solved by GSAP Helper,

Recommended Posts

 

I've been working with GSAP for quite some time now, utilizing the GSAP Premium Version. Specifically, I integrate GSAP into next.js applications (SSR). I've reviewed numerous documentation resources on GSAP/next.js and believe I'm employing GSAP according to best practices. For the most part, everything functions smoothly.

 

However, I'm encountering issues with the Scrolltrigger. Whenever I bind animations to a Scrolltrigger that uses a React Ref (useRef) as a "trigger," errors consistently arise.

 

During the initial load of a very long page, components on the page utilizing a Scrolltrigger sometimes throw an error: "Cannot read properties of undefined (reading 'end')." This problem seems to be related to the Scrolltrigger not having an element available. It is also the case that if I set the trigger via React ref, an error is thrown, but if the trigger is set via CSS class, no error is displayed.

 

scrollTrigger: {
   invalidateOnRefresh: true,
   start: 'top center',
   trigger: containerRef.current // throws errors sometimes
}
scrollTrigger: {
   invalidateOnRefresh: true,
   start: 'top center',
   trigger: '.container' // throws no error, seems not working properly all the time
}

 

According to the documentation, there's an option to set nullTargetWarn: false in gsap.config, but this doesn't suppress the errors being thrown. Somehow, this seems to be related to SSR of the component, as the errors seem to disappear when I don't load the React component via SSR.

 

I'm employing common patterns, such as "useIsomorphicLayoutEffect" or checking within the hook if the Ref element exists. However, this doesn't seem to resolve the issue either.

 

import { useEffect, useLayoutEffect } from 'react'

export const useIsomorphicLayoutEffect =
    typeof window !== 'undefined' ? useLayoutEffect : useEffect
const List = ({ title, titleSize = 2, subtitle, items }) => {
    const containerRef = useRef()
    const listItemsRef = useRef([])

    useIsomorphicLayoutEffect(() => {
        if (!containerRef.current) return

        const ctx = gsap.context(() => {
            gsap.to(
                listItemsRef.current,
                {
                    clipPath: 'polygon(0% 100%, 100% 100%, 100% 0%, 0% 0%)',
                    duration: 1,
                    opacity: 1,
                    scrollTrigger: {
                        invalidateOnRefresh: true,
                        start: 'top center',
                        trigger: containerRef.current
                    },
                    stagger: 0.2,
                    y: 0
                },
                0
            )
        }, containerRef)

        return () => ctx.revert()
    }, [])

    return (
        <div ref={containerRef}>
      ...
gsap.config({
    nullTargetWarn: false
})

The error is quite ugly because on the production environment, the entire frontend crashes if the error is thrown and not caught manually.

Does anyone have any tips on what might be causing this?

4.png

 

 

 

Link to comment
Share on other sites

  • Solution

Hi there! I see you're using React -

Proper cleanup is very important with frameworks, but especially with React. React 18 runs in strict mode locally by default which causes your useEffect() and useLayoutEffect() to get called TWICE.

 

Since GSAP 3.12, we have the useGSAP() hook (the NPM package is here) that simplifies creating and cleaning up animations in React (including Next, Remix, etc). It's a drop-in replacement for useEffect()/useLayoutEffect(). All the GSAP-related objects (animations, ScrollTriggers, etc.) created while the function executes get collected and then reverted when the hook gets torn down.

 

Here is how it works:

const container = useRef(); // the root level element of your component (for scoping selector text which is optional)

useGSAP(() => {
  // gsap code here...
}, { dependencies: [endX], scope: container }); // config object offers maximum flexibility

Or if you prefer, you can use the same method signature as useEffect():

useGSAP(() => {
  // gsap code here...
}, [endX]); // simple dependency Array setup like useEffect()

This pattern follows React's best practices.

 

We strongly recommend reading the React guide we've put together at https://gsap.com/resources/React/

 

If you still need help, here's a React starter template that you can fork to create a minimal demo illustrating whatever issue you're running into. Post a link to your fork back here and we'd be happy to take a peek and answer any GSAP-related questions you have. Just use simple colored <div> elements in your demo; no need to recreate your whole project with client artwork, etc. The simpler the better. 

  • Like 1
Link to comment
Share on other sites

35 minutes ago, GSAP Helper said:

Hi there! I see you're using React -

Proper cleanup is very important with frameworks, but especially with React. React 18 runs in strict mode locally by default which causes your useEffect() and useLayoutEffect() to get called TWICE.

 

Since GSAP 3.12, we have the useGSAP() hook (the NPM package is here) that simplifies creating and cleaning up animations in React (including Next, Remix, etc). It's a drop-in replacement for useEffect()/useLayoutEffect(). All the GSAP-related objects (animations, ScrollTriggers, etc.) created while the function executes get collected and then reverted when the hook gets torn down.

 

Here is how it works:

const container = useRef(); // the root level element of your component (for scoping selector text which is optional)

useGSAP(() => {
  // gsap code here...
}, { dependencies: [endX], scope: container }); // config object offers maximum flexibility

Or if you prefer, you can use the same method signature as useEffect():

useGSAP(() => {
  // gsap code here...
}, [endX]); // simple dependency Array setup like useEffect()

This pattern follows React's best practices.

 

We strongly recommend reading the React guide we've put together at https://gsap.com/resources/React/

 

If you still need help, here's a React starter template that you can fork to create a minimal demo illustrating whatever issue you're running into. Post a link to your fork back here and we'd be happy to take a peek and answer any GSAP-related questions you have. Just use simple colored <div> elements in your demo; no need to recreate your whole project with client artwork, etc. The simpler the better. 

Thank you for your answer. This really seems to solve my problem, as far as i can see. First test ist positive, the described error is not showing anymore. I hope in deeper tests, this works. But  useGSAP seems like a Gamechanger.

  • Like 1
Link to comment
Share on other sites

19 hours ago, Rodrigo said:

Hi,

 

Also this video can definitely help:

 

Happy Tweening!

 

Unfortunately, I have a very strange behavior after installing @gsap/react via yarn. I have installed GSAP in a premium version and deployed it to Vercel. Everything works and the license key is recognized. Exactly the same deployment, only adding @gsap/react, throws an error on Vercel: Request failed "403 Forbidden".

?

 

Link to comment
Share on other sites

Hi,

 

Try removing the lock file from your repo and pushing that again and see if the installation works.

 

If that doesn't work you'll have to add your privjs token to the .npmrc file in order to install it for the first time, then you can remove the token from the .npmrc file and it should work for future deploys. Hopefully this is a private repo so your token doesn't get exposed.

 

Hopefully this helps.

Happy Tweening!

  • Like 1
Link to comment
Share on other sites

  • 5 weeks later...
On 3/20/2024 at 1:49 PM, GSAP Helper said:

Hi there! I see you're using React -

Proper cleanup is very important with frameworks, but especially with React. React 18 runs in strict mode locally by default which causes your useEffect() and useLayoutEffect() to get called TWICE.

 

Since GSAP 3.12, we have the useGSAP() hook (the NPM package is here) that simplifies creating and cleaning up animations in React (including Next, Remix, etc). It's a drop-in replacement for useEffect()/useLayoutEffect(). All the GSAP-related objects (animations, ScrollTriggers, etc.) created while the function executes get collected and then reverted when the hook gets torn down.

 

Here is how it works:

const container = useRef(); // the root level element of your component (for scoping selector text which is optional)

useGSAP(() => {
  // gsap code here...
}, { dependencies: [endX], scope: container }); // config object offers maximum flexibility

Or if you prefer, you can use the same method signature as useEffect():

useGSAP(() => {
  // gsap code here...
}, [endX]); // simple dependency Array setup like useEffect()

This pattern follows React's best practices.

 

We strongly recommend reading the React guide we've put together at https://gsap.com/resources/React/

 

If you still need help, here's a React starter template that you can fork to create a minimal demo illustrating whatever issue you're running into. Post a link to your fork back here and we'd be happy to take a peek and answer any GSAP-related questions you have. Just use simple colored <div> elements in your demo; no need to recreate your whole project with client artwork, etc. The simpler the better. 

Unfortunately, I still have this error, which is caused by ScrollTrigger and is causing my entire app to crash in production. To isolate the problem, I have created a CodeSandbox. The error can be reproduced here. https://codesandbox.io/p/devbox/gsap-79mr6f

1. Navigate to the "Home" page.

2. Reload the page using a hard refresh.

3. Scroll all the way down.

4. Navigate to "About".

 

The error can also be reproduced by scrolling all the way down on the "About" page and then hard refreshing the page. If the page is reloaded without scrolling down, there is no error.

 

Do you have any suggestions for what might be wrong with the way ScrollTrigger is being used? The ScrollTriggers are integrated into the "HeroIntro" and "TextImage" components.

 

I believe I'm using the commonly recommended methods and the new useGSAP hook. I'm actually quite a fan of GSAP, but the interaction with Next.js and ScrollTrigger is proving to be quite cumbersome.

 

 

 

Link to comment
Share on other sites

Hi,

 

Sorry about the issues but the demo URL is not really working, I see a lot of previews but I keep getting a 502 error in them. It seems that the dev server is exiting with an error so you might want to check that.

 

If possible create a demo in Stackblitz and not use a git repo since that doesn't really allow us to fork the demo, since we need to fork the entire repo as well and that further complicates things.

 

Happy Tweening!

Link to comment
Share on other sites

2 hours ago, Rodrigo said:

Hi,

 

Sorry about the issues but the demo URL is not really working, I see a lot of previews but I keep getting a 502 error in them. It seems that the dev server is exiting with an error so you might want to check that.

 

If possible create a demo in Stackblitz and not use a git repo since that doesn't really allow us to fork the demo, since we need to fork the entire repo as well and that further complicates things.

 

Happy Tweening!

Sorry i am not very familiar with codesandbox, but https://79mr6f-3000.csb.app/ preview:3000 should work, not?

 

Alternative here a Stackblitz: https://stackblitz.com/edit/stackblitz-starters-mxw6gv

 

Link to comment
Share on other sites

I believe that's the issue that was already reported and patched in this thread related to once: true

 

The patch hasn't been released yet, but it's very easy to work around by just creating a simple ScrollTrigger first (it doesn't need to do anything). 

 

https://stackblitz.com/edit/stackblitz-starters-vynow2?file=src%2Fcomponents%2FHeroIntro%2FHeroIntro.js

 

Does that clear things up? 

Link to comment
Share on other sites

5 hours ago, GreenSock said:

I believe that's the issue that was already reported and patched in this thread related to once: true

 

The patch hasn't been released yet, but it's very easy to work around by just creating a simple ScrollTrigger first (it doesn't need to do anything). 

 

https://stackblitz.com/edit/stackblitz-starters-vynow2?file=src%2Fcomponents%2FHeroIntro%2FHeroIntro.js

 

Does that clear things up? 

Hi. Thank you for your answer. I don't think this relates to 'once' in my case. I just integrated and tested it in my real-life project, and I'm still getting the error. Once ist not used here.

 

import { useRef } from 'react'

import { gsap, ScrollTrigger, useGSAP } from '~/services/gsap'

import * as Styled from './Circle.styled'

const Circle = ({ speed, className, ...rest }) => {
    const containerRef = useRef()

    useGSAP(
        () => {
            if (!containerRef?.current) return

            ScrollTrigger.create({ end: 1, start: 0 })

            gsap.to('[data-speed]', {
                ease: 'none',
                scrollTrigger: {
                    invalidateOnRefresh: true,
                    scrub: true,
                    start: 'top bottom',
                    trigger: containerRef.current
                },
                y: (i, el) => {
                    return (
                        containerRef.current.offsetHeight *
                        parseFloat(el.getAttribute('data-speed'))
                    )
                }
            })
        },
        { dependencies: [containerRef], scope: containerRef }
    )

    return (
        <div ref={containerRef} className={className}>
            <Styled.Circle data-speed={speed} {...rest} />
        </div>
    )
}

export default Circle

Other ideas?

 

 

Screenshot 2024-04-22 091651.png

Link to comment
Share on other sites

6 hours ago, GreenSock said:

I believe that's the issue that was already reported and patched in this thread related to once: true

 

The patch hasn't been released yet, but it's very easy to work around by just creating a simple ScrollTrigger first (it doesn't need to do anything). 

 

https://stackblitz.com/edit/stackblitz-starters-vynow2?file=src%2Fcomponents%2FHeroIntro%2FHeroIntro.js

 

Does that clear things up? 

By the way, for me it seems like the error ist still there, also in your fork. Just navigate to the "about" page, scroll all the way down, and refresh (sometimes more than one time). 

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