zjebinsky Posted May 7, 2023 Posted May 7, 2023 Hey Folks, I'm a relatively new GSAP user and Club Greensock member and I've encountered on issue with the scrolltrigger plugin. I tried to recreated the problem in the stackblitz with react provided by some1 from GSAP team in a different thread i read (i hope it's not an issue since I'm mainly a react developer). https://stackblitz.com/edit/react-ynqg27?file=src/App.js I also made a quick video of the issue in on my dev server to make sure i explain the issue as much as i can (don't mind the birds in the background :D) - And also here is my component code import {gsap} from "gsap"; import {ScrollTrigger} from "gsap/all"; import {useEffect} from "react"; import {Link} from "react-router-dom"; import {cursorEnterAnimation, cursorLeaveAnimation} from "../../utils/animations"; import {SplitText} from "gsap/all"; const Work = () => { useEffect(() => { gsap.registerPlugin(ScrollTrigger); gsap.registerPlugin(SplitText); ScrollTrigger.create({ trigger: "#project-container", start: "top 40%", end: "bottom 40%", scrub: 1, markers: true, pin: "#text-container", }); }, []); return ( <div className="flex w-full flex-col items-center justify-between text-white"> <div id="project-container" className="relative flex h-[170vh] items-center justify-center"> <div className="mr-[20vw] h-[60vh] w-[600px] bg-red-400"></div> <div id="text-container" className="absolute top-0 flex flex-col items-center justify-center text-primary" > <h1 className="text-center text-8xl font-bold">TITLE</h1> <h2 className="mt-5 text-center font-grandslang text-xl font-medium"> Project & Development </h2> <button className="mt-12 text-center font-medium tracking-widest underline"> VIEW PROJECT </button> </div> </div> <div className="flex h-[170vh] items-center justify-center"> <div className="mr-[20vw] h-[60vh] w-[600px] bg-red-400"></div> </div> </div> ); }; export default Work; It seem's like the title dissapears when the starter markers meet and appears back after end markers meet at the end of the page. Then it appears in the center again on the way back and stays there untill the start markers again. Can you please tell me what I'm missing?
Solution akrdesign Posted May 7, 2023 Solution Posted May 7, 2023 Actually I'm away from my laptop, so that's why I am give you one example of ScrollTrigger pin problem in react through link ? and the link is https://codesandbox.io/embed/pin-using-gsap-in-react-forked-m5ku4c?file=/src/App.js&codemirror=1 So basically you need to create ScrollTrigger inside the gsap context api. I hope this is helpful for you. And if you want know more about gsap context just read the doc. 3
zjebinsky Posted May 7, 2023 Author Posted May 7, 2023 15 minutes ago, akrdesign said: Actually I'm away from my laptop, so that's why I am give you one example of ScrollTrigger pin problem in react through link ? and the link is https://codesandbox.io/embed/pin-using-gsap-in-react-forked-m5ku4c?file=/src/App.js&codemirror=1 So basically you need to create ScrollTrigger inside the gsap context api. I hope this is helpful for you. And if you want know more about gsap context just read the doc. Thank you so much for such a fast and friendly response! I did not realize that context is such an important thing when using GSAP with React! I havent seen the post about it earlier. I'll dive deep into that now. Here is the updated code that works just like i wanted to (for anyone that encounters the same issue!) import {gsap} from "gsap"; import {ScrollTrigger} from "gsap/all"; import {useEffect, useRef} from "react"; //import {Link} from "react-router-dom"; //import {cursorEnterAnimation, cursorLeaveAnimation} from "../../utils/animations"; import {SplitText} from "gsap/all"; gsap.registerPlugin(ScrollTrigger); gsap.registerPlugin(SplitText); const Work = () => { let component = useRef(null); useEffect(() => { let ctx = gsap.context(() => { gsap.to("#text-container", { scrollTrigger: { trigger: "#project-container", start: "top 40%", end: "bottom 40%", pin: "#text-container", pinSpacing: false, markers: true, }, }); }, component); return () => ctx.revert(); }, []); return ( <div ref={component} className="flex w-full flex-col items-center justify-between text-white"> <div id="project-container" className="relative flex h-[170vh] items-center justify-center"> <div className="mr-[20vw] h-[60vh] w-[600px] bg-red-400"></div> <div id="text-container" className="absolute top-0 flex flex-col items-center justify-center text-primary" > <h1 className="text-center text-8xl font-bold">TITLE</h1> <h2 className="mt-5 text-center font-grandslang text-xl font-medium"> Project & Development </h2> <button className="mt-12 text-center font-medium tracking-widest underline"> VIEW PROJECT </button> </div> </div> <div className="flex h-[170vh] items-center justify-center"> <div className="mr-[20vw] h-[60vh] w-[600px] bg-red-400"></div> </div> </div> ); }; export default Work;
GreenSock Posted May 7, 2023 Posted May 7, 2023 4 hours ago, zjebinsky said: I did not realize that context is such an important thing when using GSAP with React! It isn't so much that context() is critical - the fundamental problem is that React 18+ invokes useEffect()/useLayoutEffect() TWICE in strict mode which causes a lot of people to inadvertently create multiple (duplicate) competing/conflicting animations/ScrollTriggers that are fighting for control of the same element. That's why cleanup is so important. gsap.context() just makes cleanup super easy, that's all. Glad you got it figured out. And thanks for chiming in, @akrdesign ? 2
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