GSAP animations useGSAP hook triggering simultaneously in Next.js

36 Views Asked by At

I'm encountering an issue while migrating a React project to Next.js. In the original React project, I used GSAP animations with the useGSAP hook from the @gsap/react library. The animations in each component would start only when the component scrolled into view. However, after converting the project to Next.js, all the animations in each component start simultaneously when the page loads, instead of triggering individually upon scrolling into view.

I've tried various solutions to resolve this issue, including creating a custom hook named useIsomorphicLayoutEffect to ensure that animations are triggered properly in both client and server-side rendering scenarios. Despite my efforts, I haven't been able to solve the problem.

export const useIsomorphicLayoutEffect =
  typeof window !== "undefined" ? useLayoutEffect : useEffect;  
"use client";

import gsap from "gsap";

export const Highlights = () => {
  const highlightsRef = useRef < HTMLDivElement > null;

  useIsomorphicLayoutEffect(() => {
    gsap.to("#title", {
      opacity: 1,
      y: 0,
    });
  }, []);

  return (
    <section
      ref={highlightsRef}
      id="highlights"
      className="w-screen overflow-hidden h-full sm:py-32 py-20 sm:px-10 px-5 bg-zinc"
    >
      <div className="md:max-w-screen-2xl">
        <div className="mb-12 w-full md:flex items-end justify-between">
          <h2
            id="title"
            className="text-gray lg:text-6xl md:text-5xl text-3xl lg:mb-0 mb-5 font-medium opacity-0 translate-y-20"
          >
            Get the highlights.
          </h2>
        </div>
      </div>
    </section>
  );
};

Using useGSAP() hook

page.tsx

import { Hero } from "@/components/hero";
import { Highlights } from "@/components/highlights";

const Home = () => {
    return (
        <>
            <Hero />
            <Highlights />
        </>
    )
}
export default Home;

components/highlights.tsx

"use client";

import gsap from "gsap"
import { useGSAP } from "@gsap/react"
import { Hero } from "./hero";
import { useRef } from "react";


export const Highlights = () => {

    const highlightsRef = useRef<HTMLDivElement>(null);
    // const highlightsRef = document.getElementById("highlights");

    useGSAP(() => {
        gsap.to("#title", { 
            opacity: 1, 
            y: 0 
        });
        gsap.to(".link", { 
            opacity: 1, 
            y: 0, 
            duration: 1, 
            stagger: 0.25 
        });
    }, []);

    return (
        <section ref={highlightsRef} id="highlights" className="w-screen overflow-hidden h-full sm:py-32 py-20 sm:px-10 px-5 bg-zinc">
            <div className="md:max-w-screen-2xl">
                <div className="mb-12 w-full md:flex items-end justify-between">
                    <h2 
                        id="title" 
                        className="text-gray lg:text-6xl md:text-5xl text-3xl lg:mb-0 mb-5 font-medium opacity-0 translate-y-20"
                    >
                        Get the highlights.
                    </h2>
                </div>
            </div>
        </section>
    )
}

layout.tsx

import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";

import { Navbar } from "@/components/navbar";

const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <div className="h-full">
        <Navbar />
        <main>
          {children}
        </main>
        </div>
      </body>
    </html>
  );
}
0

There are 0 best solutions below