Framer Motion ile Sayfa İlk Göründüğünde Canlanan Bir Sayaç Bileşeni
// apps/web/src/components/AnimatedCounter.tsx
export function AnimatedCounter({ value, suffix = "" }: { value: number; suffix?: string }) {
const ref = useRef<HTMLSpanElement>(null);
const isInView = useInView(ref, { once: true, margin: "-80px" });
const motionValue = useMotionValue(0);
const springValue = useSpring(motionValue, { damping: 24, stiffness: 90 });
const [display, setDisplay] = useState(0);
useEffect(() => {
if (isInView) motionValue.set(value);
}, [isInView, value, motionValue]);
useEffect(() => {
return springValue.on("change", (latest) => setDisplay(Math.round(latest)));
}, [springValue]);
return <span ref={ref}>{display}{suffix}</span>;
}
Üç ayrı motion primitive'i, üç ayrı görev
useMotionValue ham hedef değeri (value) tutuyor — React state değil, Framer Motion'ın kendi reaktif sistemi, her değişiklikte component'i yeniden render etmiyor. useSpring, bu ham değeri bir yay fiziği simülasyonundan geçirip pürüzsüz bir ara-değer akışına çeviriyor (damping/stiffness yayın "sertliğini" belirliyor). useState ise bu akıştaki değerleri gerçek DOM'a yazdırmak için gereken tek React state — springValue.on("change", ...) her ara-değeri yakalayıp display'i güncelliyor.
useInView({ once: true }) neden var
Bu sayaç, sayfa yüklendiği anda değil, kullanıcı o bölüme scroll ettiğinde animasyonlu sayıyor. once: true olmadan, kullanıcı yukarı/aşağı scroll ettikçe eleman görünür alana her girdiğinde animasyon yeniden tetiklenirdi — rahatsız edici bir tekrar. margin: "-80px" ise elemanın viewport'a tam girmesini beklemeden, 80px kala tetiklemeyi başlatıyor; kullanıcı elemanın kendisini gördüğü an animasyon zaten bir miktar ilerlemiş oluyor.
Neden düz bir setInterval sayaç değil
Yay fiziği (spring), lineer bir sayaçtan (0, 1, 2, ... 8 sabit adımlarla) farklı olarak hıza ivme kazandırıp yavaşça yerine oturan organik bir his veriyor — sayı 0'dan hedefe "zıplayarak" değil "yerçekimiyle yavaşlayarak" ulaşıyor. Bu, stiffness: 90, damping: 24 gibi iki sayıyla ayarlanabilen, tekrar kullanılabilir bir davranış; her yeni sayaç ihtiyacı için animasyon eğrisini elle tasarlamak gerekmiyor.