I have a framer-motion based Counter component. I want it to start the account once the component is in view. Currently, The count happens on page-load, the only thing that happens is the component jumps up once in view:
export default function Counter({ from, to }: CounterProps) {
const nodeRef = useRef<HTMLParagraphElement>(null);
useEffect(() => {
const node = nodeRef.current;
const controls = animate(from, to, {
duration: 1,
onUpdate(value) {
if (node) {
node.textContent = Math.floor(value).toLocaleString() + "+";
}
},
});
return () => controls.stop();
}, [from, to]);
return (
<motion.p
variants={{
visible: { opacity: 1, scale: 1 },
hidden: { opacity: 0, scale: 0 },
}}
initial="hidden"
whileInView="visible"
className="font-black text-6xl absolute top-[70%] text-center items-baseline justify-center grayscale filter object-contain rounded-2xl"
ref={nodeRef}></motion.p>
);
}
I also tried using reac-intersection-observer but it does not even render:
"use client";
import { animate } from "framer-motion";
import { useEffect, useRef } from "react";
import { useInView } from "react-intersection-observer";
interface CounterProps {
from: number;
to: number;
}
export default function Counter({ from, to }: CounterProps) {
const nodeRef = useRef<HTMLParagraphElement>(null);
const [ref, inView] = useInView({
triggerOnce: true, // Only trigger the animation once
threshold: 0.5, // Adjust the threshold as needed
});
useEffect(() => {
const node = nodeRef.current;
if (inView) {
const controls = animate(from, to, {
duration: 1,
onUpdate(value) {
if (node) {
node.textContent = Math.floor(value).toLocaleString() + "+";
}
},
});
return () => controls.stop();
}
}, [from, to, inView]);
return (
<p
className="font-black text-6xl absolute top-[70%] text-center items-baseline justify-center grayscale filter object-contain rounded-2xl"
ref={ref}
></p>
);
}