andiwi Posted January 21, 2022 Share Posted January 21, 2022 Hi @all, thank you for this awesome library! Unfortunately, I am facing issues with the ScrollTrigger effect inside my nextjs production build. I hope you can help me. The ScrollTrigger effect works perfectly fine, when I start the nextjs project in development ("next dev"). However, when I build a production build and host the production build via a web server, the element to which the ScrollTrigger effect is attached to is not displayed from time to time. I created a simple codesandbox where you can reproduce the behaviour: https://codesandbox.io/s/nextjs-gsap-scrolltrigger-bug-qtgfl?file=/pages/index.js It works fine inside the codesandbox (development) but when built and deployed to a server https://csb-qtgfl-nml1dj1ep-andiwi.vercel.app/ the headline is not displayed from time to time. To reproduce go to https://csb-qtgfl-nml1dj1ep-andiwi.vercel.app/ and refresh the page multiple times until the headline is not displayed anymore. I followed the official resources https://greensock.com/react/ and https://greensock.com/st-mistakes/ and also read through forum posts like https://greensock.com/forums/topic/27012-scrolltrigger-and-array-of-refs-in-react/ but did not find a solution for the problem. I am new to gsap. Do you spot any wrong usage of the library? The same setup works in a simple react app (e.g. create-react-app). Would be great if you have any ideas how to solve this error. I am trying to solve the error for days now without any success and I am out of ideas. Thank you! Link to comment Share on other sites More sharing options...
Cassie Posted January 21, 2022 Share Posted January 21, 2022 Hey there! I would first try using useLayoutEffect instead of useEffect. Also - console.log(h1Ref.current) in your useLayoutEffect - see if you can work out what the difference is between reloads. Link to comment Share on other sites More sharing options...
andiwi Posted January 21, 2022 Author Share Posted January 21, 2022 Thank you for your quick response. I tried to use useLayoutEffect. However, when using the useLayoutEffect hook, the ScrollTrigger effect does not work at all. Here is the example: https://codesandbox.io/s/nextjs-gsap-scrolltrigger-bug-uselayouteffect-vxxd9?file=/pages/index.js Deployed: https://csb-vxxd9-andiwi.vercel.app/ EDIT: Indeed, what I can observe is that the console.log output is sometimes different, but the bug occurs in both cases. It looks like the DOM is not ready when gsap effect is initialised. console.log output (example 1): console.log output (example 2): Link to comment Share on other sites More sharing options...
Cassie Posted January 21, 2022 Share Posted January 21, 2022 This example seems to work on codesandbox. Not sure why it wouldn't be working for you? I don't think you need to be killing the animation, and you had paused:trueset which isn't needed on a scrollTriggered animation. It will be paused anyway until it hits the trigger point.https://codesandbox.io/s/nextjs-gsap-scrolltrigger-bug-uselayouteffect-forked-eu2v9?file=/pages/index.js Link to comment Share on other sites More sharing options...
andiwi Posted January 21, 2022 Author Share Posted January 21, 2022 Thank you for the hints. I removed the paused:true and the animation cleanup (although on this page a cleanup is recommended: https://greensock.com/react/#cleaning-up ) Yes, it works on codesandbox (which is the development setup), but when I build and deploy the production build the headline is not displayed. https://codesandbox.io/s/nextjs-gsap-scrolltrigger-bug-uselayouteffect-v2-qf0w1?file=/pages/index.js (working dev) https://csb-qf0w1-p1ozjx5rl-andiwi.vercel.app/ (not working production build) Link to comment Share on other sites More sharing options...
OSUblake Posted January 21, 2022 Share Posted January 21, 2022 Your console.log statements show that GSAP is animating, but I have no idea why it's not visible. I would try another test animation, like say something else that doesn't use .from() or opacity for a sanity check. Link to comment Share on other sites More sharing options...
andiwi Posted January 21, 2022 Author Share Posted January 21, 2022 (edited) I just tested a gsap.from and a gsap.to with and without opacity animation (without scrollTrigger). For example: useLayoutEffect(() => { gsap.from(h1Ref.current, { rotation: 45, y: 200, duration: 1, opacity: 0, // also tested without this line }); }, []); All examples are working fine in production build. Maybe an issue in the scrollTrigger plugin? EDIT: I also tested the same effect with my scrollTrigger which works fine with a gsap.to but when using the gsap.from in combination with scrollTrigger the animation doesn't get played correctly. So it might be a bug of scrollTrigger in combination with a gsap.from ? useLayoutEffect(() => { gsap.to(h1Ref.current, { // gsap.to is working fine, gsap.from -> not working scrollTrigger: { id: 1, trigger: h1Ref.current, start: "top bottom", toggleActions: "play none none reverse", }, rotation: 45, y: 200, duration: 1, opacity: 0, // also tested without this line }); }, []); Edited January 21, 2022 by andiwi additional info Link to comment Share on other sites More sharing options...
OSUblake Posted January 21, 2022 Share Posted January 21, 2022 I doubt it because this shows the h1 is being animated. See the inline opacity and transform style. I also noticed that you are animating the trigger, which you shouldn't do as that will mess up ScrollTrigger's calculations. Try animating a wrapper element instead. 1 Link to comment Share on other sites More sharing options...
andiwi Posted January 22, 2022 Author Share Posted January 22, 2022 (edited) I set the trigger to a wrapper div. Unfortunately, this didn't solve the issue. Is setting the trigger to the to-be-animated element bad in general when using ScrollTrigger with a gsap.from? I just followed the simple example of https://greensock.com/docs/v3/Plugins/ScrollTrigger What is interesting: when I wrap the gsap animation into a timeout to push it to the JS event loop, the animation at least gets played most of the time, but still not every-time (refresh browser multiple times until the animation gets stuck again). So there might be some race condition between DOM painting of react/nextjs static rendering optimization and gsap initialisation. Example with scroll trigger on a wrapper div: https://codesandbox.io/s/nextjs-gsap-scrolltrigger-bug-v3-uselayouteffect-another-trigger-ys92e?file=/pages/index.js Without timeout: https://csb-ys92e-nol25vd68-andiwi.vercel.app/ With timeout: https://csb-ys92e-nol25vd68-andiwi.vercel.app/with_timeout EDIT: I once again tested the code with simple react -> also not working: https://codesandbox.io/s/react-gsap-scrolltrigger-not-working-gy3kn Edited January 22, 2022 by andiwi add simple react example 1 Link to comment Share on other sites More sharing options...
Solution Cassie Posted January 22, 2022 Solution Share Posted January 22, 2022 Ah yes! Got it. Looks like it's down to a regression in the latest version. So sorry about this @andiwi Fixing options! Step back the version to 3.8 Use the latest beta Fix it for the current version by setting lazy: false on your .from() tween(s). 4 Link to comment Share on other sites More sharing options...
Cassie Posted January 22, 2022 Share Posted January 22, 2022 Working 3.9 examplehttps://codesandbox.io/s/react-gsap-scrolltrigger-not-working-forked-xl1j6?file=/src/App.js 1 Link to comment Share on other sites More sharing options...
andiwi Posted January 22, 2022 Author Share Posted January 22, 2022 Ah! @Cassie, you are my hero! 😊👏 Also many thanks to @OSUblake for helping here. Where can I buy you a cup of coffee? ☕️ 2 1 Link to comment Share on other sites More sharing options...
Cassie Posted January 22, 2022 Share Posted January 22, 2022 Oh no don't worry about that. Very happy to help! ☺️ Thank you for the kind offer though. To answer this too... Quote I set the trigger to a wrapper div. Unfortunately, this didn't solve the issue. Is setting the trigger to the to-be-animated element bad in general when using ScrollTrigger with a gsap.from? It's a bad plan if you're going to be moving the trigger element as it can mess up calculations - if you're just doing an opacity fade it'll be fine. 3 Link to comment Share on other sites More sharing options...
nagman Posted April 18, 2022 Share Posted April 18, 2022 Great! I had exactly the same issue and had a hard time finding a topic about it. I solved it by upgrading gsap to the beta version: yarn add gsap@latest Link to comment Share on other sites More sharing options...
TajSSS Posted December 12, 2023 Share Posted December 12, 2023 Does anyone still have issues with Next13/14. I cannot make it to work no matter what I try. Especially, ScrollTrigger and .from(). 1 Link to comment Share on other sites More sharing options...
GreenSock Posted December 12, 2023 Share Posted December 12, 2023 Sure, GSAP and ScrollTrigger work great with Next. If you need help, please post a minimal demo that clearly illustrates the problem. Here is a starter template you can fork: https://stackblitz.com/edit/nextjs-5cm4qn I bet you're just not doing proper cleanup which is essential in React. Please read https://gsap.com/react You might also want to check out the brand new useGSAP() hook that we'll be announcing soon: https://www.npmjs.com/package/@gsap/react Link to comment Share on other sites More sharing options...
JPPdesigns Posted January 23 Share Posted January 23 I am having serious issues with GSAP scroll trigger + NextJS 14.1.0. In storybook it works as you would expect, markers are in the correct place etc. As soon as I run the same components in my nextj app dev or production... My start & end markers are in totally different places with the same settings when rendered in storybook vs nextjs. You can see the start and end markers are overlapping in my next js version and the storybook version the start is where I would expect it to be Link to comment Share on other sites More sharing options...
GreenSock Posted January 23 Share Posted January 23 3 hours ago, JPPdesigns said: I am having serious issues with GSAP scroll trigger + NextJS 14.1.0. In storybook it works as you would expect, markers are in the correct place etc. As soon as I run the same components in my nextj app dev or production... My start & end markers are in totally different places with the same settings when rendered in storybook vs nextjs. Howdy, @JPPdesigns. It's pretty tough for us to troubleshoot blind - would you mind providing a minimal demo (like a Stackblitz) that clearly illustrates the issue? I wonder if you're not doing proper cleanup or if you are doing routing in such a way that doesn't fire a "load" event which would trigger the ScrollTrigger.refresh(). You could just make sure you call a ScrollTrigger.refresh() when your content loads and is finished shifting the DOM layout around. Here's a Stackblitz you can fork: https://stackblitz.com/edit/nextjs-5cm4qn Are you using the new useGSAP() hook? And the latest version of GSAP? Link to comment Share on other sites More sharing options...
JPPdesigns Posted January 23 Share Posted January 23 Sorry @GreenSock really hard to create a stackblitz for this issue as there is SO much setup to give you a minimal demo... What I noticed is if I have a dependency array set and pinSpacing: false then the animation is all out of whack. I am on the latest version of everything With pinSpacing false in nextjs with pinSpacing false in Storybook Link to comment Share on other sites More sharing options...
GreenSock Posted January 24 Share Posted January 24 Are you using the useGSAP() hook? My guess is you're not doing proper cleanup. Did you try setting revertOnUpdate: true in the config object? I'm curious why you'd have a dependency Array for something with a ScrollTrigger. Again, it's super duper hard for us to troubleshoot blind like this. Link to comment Share on other sites More sharing options...
JPPdesigns Posted January 24 Share Posted January 24 Yeah I am using the useGSAP hook. Below is my code snippet that I have ended up with which appears to work in my production build now but not in dev mode. Could dev mode be impacted by useEffect running twice in strict mode? useGSAP( () => { matchMediaRef.current = gsap.matchMedia().add( { isMobile: '(max-width: 768px)', isDesktop: '(min-width: 769px)', }, (context) => { const { isMobile } = context.conditions || {}; gsap.set(firstViewRef.current, { opacity: 1, lazy: false, }); gsap.set(scrolledViewRef.current, { lazy: false, opacity: 0, yPercent: 0, scale: 0.7, }); timelineRef.current = gsap .timeline({ scrollTrigger: { trigger: containerRef.current, start: 'top 44px', end: 'center 44px', invalidateOnRefresh: true, pin: true, pinSpacing: false, scrub: true, markers: isDev, }, }) .to(firstViewRef.current, { ...(isMobile ? { yPercent: -40, xPercent: -30, } : { yPercent: -38, xPercent: -15, }), opacity: 0.8, scale: 0.3, }) .to( scrolledViewRef.current, { opacity: 1, scale: 1, yPercent: 0, xPercent: 0, }, 0.2 ); } ); }, { scope: containerRef, revertOnUpdate: true, } ); Link to comment Share on other sites More sharing options...
Rodrigo Posted January 24 Share Posted January 24 Hi, 3 hours ago, JPPdesigns said: Could dev mode be impacted by useEffect running twice in strict mode? Nope, useGSAP takes care of animation cleanup for you so that shouldn't cause any issues. Do you have a minimal demo that clearly illustrates the problem you're facing? Honestly I don't see anything in that code that should break on development but work on production. The only thing that looks odd is the fact that you have revertOnUpdate: true but you don't have any dependencies array in your useGSAP hook, revertOnUpdate is to revert everything when one of the dependencies is updated, but for that you actually need a dependencies array. Happy Tweening! Link to comment Share on other sites More sharing options...
JPPdesigns Posted January 24 Share Posted January 24 Yeah it was left in from a previous implementation with a dependency array. Good news is this setup is working as expected in production. I wish I could post a video showing what it looks like in dev mode. A minimal demo is pretty time consuming so I will try to create one in the coming days but now the production version is working as expected 😅 AND I can test in storybook as opposed to nextjs dev mode. I guess we are in a better place. I will remove revertOnUpdate too. Will get back to you with a stackblitz 1 1 Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now