I can't figure out for the life of me why my component is initializing twice (and in the process registering event handlers twice that torch my animations). I thought the useGSAP hook mitigated this issue but perhaps I misunderstand or am utilizing it incorrectly.
Thanks in advance.
"use client"
import React, { useRef } from "react";
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import { useGSAP } from "@gsap/react";
import "./styles/skewgallery.css";
export const SkewGallery = ({ items }) => {
gsap.registerPlugin(useGSAP, ScrollTrigger);
const mainRef = useRef();
const overlayRef = useRef();
const timelineRef = useRef(null);
useGSAP(
(context, contextSafe) => {
const itemsArray = gsap.utils.toArray(".skew-item");
console.log("initializing");
if (!timelineRef.current) {
timelineRef.current = gsap.timeline({ paused: true });
}
itemsArray.forEach((item) => {
gsap.fromTo(
item,
{
opacity: 0,
yPercent: 20,
ease: "power4.out",
stagger: 1,
},
{
opacity: 1,
yPercent: 0,
scrollTrigger: {
trigger: item,
start: "top bottom",
end: "50% 85%",
scrub: 1,
},
}
);
const handleClick = contextSafe(() => {
const timeline = timelineRef.current;
console.log("doing it");
timeline.clear();
timeline.to(
item,
{
rotation: 5,
scale: 1.5,
duration: 0.75,
zIndex: 2,
ease: "Back.easeOut",
},
"<"
);
timeline.to(
overlayRef.current,
{
zIndex: 1,
opacity: 0.85,
},
"<"
);
itemsArray.forEach((otherItem) => {
if (otherItem !== item) {
timeline.to(
otherItem,
{
scale: 0.95,
duration: 0.5,
ease: "power2.out",
},
"<"
);
}
});
timeline.play();
});
item.addEventListener("click", handleClick);
return () => {
item.removeEventListener("click", handleClick);
};
});
console.log("overlay init");
overlayRef.current.addEventListener("click", () => {
console.log("overlay clicked");
timelineRef.current.reverse();
});
},
{ scope: mainRef, dependencies: [] }
);
return (
<>
<div ref={mainRef} className="skew">
<div ref={overlayRef} className="skew-overlay"></div>
<div className="skew-container grid grid-cols-4 gap-5 p-5 items-center h-full w-full">
{items.map((image, index) => (
<div
key={index}
className="skew-item bg-slate-500 min-h-[300px] h-full border-2 border-gray-900 rounded-lg overflow-hidden bg-cover bg-no-repeat"
>
<h2>{image.title}</h2>
</div>
))}
</div>
</div>
</>
);
};
export default SkewGallery;