Trying to solve my animation problem. I have this animation where on load, i am animating buttons, and if the animation of 4s is over, it should go to the next slide, and show a different image. On the first page load, the animation of the button is done but the image and next button is animating after 4s + some weird extra 2s? after, this weird issue it works perfectly fine every 4s the animation repeats in a loop.
Any help would be great.
"use client"
import React, { useEffect, useRef, useState } from "react"
import { animated, useSprings } from "react-spring"
import { FullscreenHero as HeroType } from "@/types/page-sections/fullscreen-hero"
import { BlockContentHero } from "@/components/shared"
type HeroProps = {
data: HeroType
}
const Hero = ({ data }: HeroProps) => {
if (!data) return null
const { content } = data
const [activeButton, setActiveButton] = useState(0)
const [hoveredButton, setHoveredButton] = useState<number | null>(null)
const [initialRender, setInitialRender] = useState(true)
const [imagesLoaded, setImagesLoaded] = useState(false) // Track if images are loaded
const imageUrls = [
"https://cdn.sanity.io/images/i4puecl6/production-v2/6d4512da62110d52ff00501a928b6224f3d4ebee-2005x1276.webp?w=1980&q=90&fit=clip&auto=format",
"https://cdn.sanity.io/images/i4puecl6/production-v2/04010ba92f6a3c5c731795dc76a8e380edbb966b-2005x1276.webp?w=1980&q=90&fit=clip&auto=format",
"https://cdn.sanity.io/images/i4puecl6/production-v2/ccf2101864730c320b84b4098c5345331f7b5487-3200x2400.webp?w=1980&q=90&fit=clip&auto=format"
]
const easeOutQuad = (t: number) => t * (2 - t)
const easeInOutCubic = (t: number) =>
t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1
useEffect(() => {
// Preload images
const preloadImages = async () => {
await Promise.all(
imageUrls.map(
(url) =>
new Promise((resolve) => {
const img = new Image()
img.src = url
img.onload = resolve
})
)
)
setImagesLoaded(true)
}
preloadImages()
}, [imageUrls])
// Start interval immediately when component mounts
useEffect(() => {
startInterval()
return () => {
if (intervalRef.current !== null) {
clearInterval(intervalRef.current)
}
}
}, [])
useEffect(() => {
// Set initial state immediately
setInitialRender(false)
}, [])
const imageSprings = useSprings(
imageUrls.length,
imageUrls.map((imageUrl, index) => ({
opacity: activeButton === index ? 1 : 0,
scale: activeButton === index ? 1.1 : 1,
config: {
duration: 200,
easing: activeButton === index ? easeInOutCubic : easeOutQuad
}
}))
)
const contentBg = [
{ text: "Zorgwijzer", link: "/work/design-declares", imageIndex: 0 },
{ text: "Creditcard", link: "/work/roadrunner-venture-studios", imageIndex: 1 },
{ text: "WorldCup", link: "/work/only-one", imageIndex: 2 }
]
const intervalRef = useRef<NodeJS.Timeout | null>(null)
const handleMouseEnter = (index: number) => {
setHoveredButton(index)
setActiveButton(index)
if (intervalRef.current !== null) {
clearInterval(intervalRef.current)
}
}
const handleMouseLeave = () => {
setHoveredButton(null)
startInterval() // Start a new interval when the mouse leaves
}
const startInterval = () => {
intervalRef.current = setInterval(() => {
setActiveButton((prev) => (prev + 1) % 3)
}, 4000)
}
return (
<section className="col-span-full text-white overflow-hidden absolute top-0 left-0 z-0 w-full h-full px-5 md:px-10 flex flex-col items-center justify-between bg-black">
<div className="h-full flex items-center place-content-center">
<h1 className="hero pt-[90px] text-center max-w-wrap z-10 mb-10">
{contentBg.map((item: any, index: number) => (
<span key={index} className="mx-2 sm:inline-flex">
<a
className={`hero overflow-hidden group text-inherit`}
href={item.link}
onMouseEnter={() => handleMouseEnter(index)}
onMouseLeave={handleMouseLeave}
>
<span
className={`mix-blend-difference z-[100] uppercase relative group-hover:mix-blend-normal`}
>
{item.text}
</span>
<span
className={`h-full absolute z-10 top-0 left-0 transition-all duration-500 bg-white ${
activeButton === index ? "animate-progress" : "opacity-0 w-0"
}`}
></span>
</a>
</span>
))}
</h1>
{/* {contentBg.map((item: any, index: number) => (
<animated.img
key={index}
src={imageUrls[index]}
alt={`Background Image ${index + 1}`}
className="absolute w-screen h-screen top-0 left-0 object-cover transition duration-500 opacity-0"
style={{
...imageSprings[index],
backgroundImage: `url(${imageUrls[index]})`
}}
/>
))} */}
</div>
<div className="absolute right-10 w-0.5 bottom-10 h-[100px] z-40">
<span className="animate-draw absolute w-full h-0 bg-white rounded-full"></span>
</div>
</section>
)
}
export default Hero