Jump to content
Search Community

ryanmac

Premium
  • Posts

    4
  • Joined

  • Last visited

Posts posted by ryanmac

  1. Thank you!  I went ahead and applied those changes but my events still seem to be firing twice.   I moved the component to stackblitz so you could take a look.

    https://stackblitzstarterskgd3hx-gyvp--3000--9e2d28a3.local-credentialless.webcontainer.io

    UPDATE: 

    Figured it out.  The solution, for my anyway, was to:

     

    1. attach the event listener directly on the element
    2. create and leverage a ref array to grab the correct instance via index.
     

      const itemRefs = useRef([]);
      const timelineRef = useRef(gsap.timeline({ paused: true }));
      const activeItem = useRef(null);
    
      itemRefs.current = [];
    
      const addToItemRefs = (el) => {
        if (el && !itemRefs.current.includes(el)) {
          itemRefs.current.push(el);
        }
      };
    
      const toggleClick = (clickedItem) => {
        if (activeItem.current === clickedItem) {
            timelineRef.current.reverse();
          return;
        }
        
        // timeline code... 

     

    <div className="skew-container grid grid-cols-4 gap-5 p-5 items-center h-full w-full">
              {items.map((image, index) => (
                <div
                  ref={addToItemRefs}
                  key={index}
                  onClick={() => toggleClick(itemRefs.current[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>

     

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

     

×
×
  • Create New...