<div id="root" class="panel center text-center"></div>
.app {
  padding: 10px;
}

.box {
  margin: 10px 0;
  will-change: transform;
}
const { useEffect, useLayoutEffect, useRef, forwardRef, useState } = React;

gsap.registerPlugin(CustomEase, CustomWiggle);
gsap.config({ trialWarn: false });

CustomWiggle.create("myWiggle", {
  wiggles: 8,
  type: "uniform"
});

gsap.registerEffect({
  name: "pulse",
  effect(targets) {
    return gsap.fromTo(targets, {
      scale: 1
    }, {
      scale: 1.5,
      repeat: 1,
      ease: "bounce",
      yoyoEase: "power3"
    });
  }
});

gsap.registerEffect({
  name: "spin",
  effect(targets) {
    return gsap.to(targets, {
      rotation: (i, el) => gsap.utils.snap(360, gsap.getProperty(el, "rotation") + 360)
    });
  }
});

gsap.registerEffect({
  name: "shake",
  effect(targets) {
    return gsap.fromTo(targets, {
      x: 0
    }, {
      x: 10, 
      ease: "myWiggle"      
    });
  }
});

const GsapEffect = forwardRef(({ children, effect, targetRef, vars }, ref) => {  
  const animation = useRef();
  
  useLayoutEffect(() => {
        
    if (gsap.effects[effect]) {
      animation.current = gsap.effects[effect](targetRef.current, vars);
    }
  }, [effect]);
  
  useEffect(() => {
    
    // forward the animation instance if a ref is passed
    if (typeof ref === "function") {
      ref(animation.current);
    } else if (ref) {
      ref.current = animation.current;
    }
  }, [ref]);
  
  return <>{children}</>;
});

const Box = forwardRef(({ children }, ref) => {
  return <div className="box" ref={ref}>{children}</div>;
});

const wrap = gsap.utils.wrap(["pulse", "spin", "shake"]);

function App() {    
  const boxRef = useRef();
  const count = useRef(0);  
  const [effect, setEffect] = useState("");   
     
  const toggle = () => {
    setEffect(wrap(count.current++));
  };
  
  return (
    <div className="app">
      <div>
        <button onClick={toggle}>Toggle</button>
      </div>
      <p>Effect: {effect}</p>
      <GsapEffect targetRef={boxRef} effect={effect}>
        <Box ref={boxRef}>Box</Box>
      </GsapEffect>
    </div>
  );
}

ReactDOM.render(<App />, document.querySelector("#root"));
View Compiled

External CSS

  1. https://codepen.io/GreenSock/pen/gOWxmWG.css

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js
  3. https://assets.codepen.io/16327/CustomEase3.min.js
  4. https://assets.codepen.io/16327/CustomWiggle3.min.js
  5. https://unpkg.co/gsap@3/dist/gsap.min.js