GSAP

January 5, 2024 (5mo ago)

Archive

New Hook Just Dropped

Over the past few years, I've primarily relied on Framer Motion for handling my animations, while incorporating GSAP from time to time, I found it to be somewhat verbose compared to Framer, especially in a React context.

But, check this out, yesterday GSAP introduced the useGSAP() hook, an addition to easily integrate GSAP with React.

Prior to this, animating elements involved wrapping them in a gsap.Context object, then, you had to use the same object's methods like .revert() or .kill() within useEffect() or useLayoutEffect()'s cleanup function to avoid memory leaks, depending if you're within an SSR context or not, along with a mandatory dependency array that you have to keep track of.

It's just a lot of overhead really to do something silly like

You'd need to

import React, { useRef, useEffect, useLayoutEffect } from 'react';
import gsap from 'gsap';

const useIsoLayoutEffect =
  typeof window !== 'undefined' ? useLayoutEffect : useEffect;

const Component: React.FC = () => {
  const container = useRef<HTMLDivElement>(null);

  useIsoLayoutEffect(() => {
    const ctx = gsap.context(() => {
      const tl = gsap.timeline({ repeat: -1, repeatDelay: 0.5 });

      tl.to('.x', {
        rotation: 360,
        duration: 2,
        borderRadius: 16,
        translateX: -150,
        ease: 'power1.inOut',
      });
      tl.to('.x', {
        rotation: -360,
        duration: 2,
        borderRadius: 0,
        translateX: 150,
        ease: 'power1.inOut',
      });
      tl.to('.x', {
        rotation: 360,
        duration: 2,
        borderRadius: 16,
        translateX: 0,
        ease: 'power1.inOut',
      });
    }, container);

    return () => ctx.revert();
  }, []);

  return (
    <div>
      <div
        ref={container}
        className="flex flex-col items-center justify-center gap-10"
      >
        <div className="x w-10 h-10 bg-red-400 rounded-2xl animate-pulse"></div>
        <div className="x w-10 h-10 bg-yellow-400 rounded-2xl animate-pulse"></div>
        <div className="x w-10 h-10 bg-green-500 rounded-2xl animate-pulse"></div>
      </div>
    </div>
  );
};

This new hook abstracts away these inconveniences, and obviates the need for explicit cleanup. So the same logic above can be written as


  useGSAP(
    () => {
      const tl = gsap.timeline({ repeat: -1, repeatDelay: 0.5 });
      tl.to('.x', {
        rotation: 360,
        duration: 2,
        borderRadius: 16,
        translateX: -150,
        ease: 'power1.inOut',
      });
      tl.to('.x', {
        rotation: -360,
        duration: 2,
        borderRadius: 0,
        translateX: 150,
        ease: 'power1.inOut',
      });
      tl.to('.x', {
        rotation: 360,
        duration: 2,
        borderRadius: 16,
        translateX: 0,
        ease: 'power1.inOut',
      });
    },
    { scope: container}
  );

It looks hella cleaner IMO, I actually like this update, I mean it's not a lot but hey, it gets the job done a lot easier so, I might use even more now, and sorry if you thought this is an educational post where I teach you about GSAP, nope, I'm just glad they introduced this new hook, that's it.