Slider Hook

A hook for creating an slider for react

Teecod3

View Profile
79 views
Jun 21, 2025
Updated Jun 21, 2025
import { gsap } from "gsap";
import { useCallback, useEffect, useRef, useState } from "react";

interface UseSliderProps {
images: string[];
autoPlayInterval_?_: number;
pauseOnHover_?_: boolean;
}

export const useSlider = ({
images,
autoPlayInterval = 5000,
pauseOnHover = true,
}: UseSliderProps) => {
const [currentIndex, setCurrentIndex] = useState(0);
const [isPlaying, setIsPlaying] = useState(true);
const [isTransitioning, setIsTransitioning] = useState(false);
const timerRef = useRef<number | null>(null);
const sliderRef = useRef<HTMLDivElement>(null);
const imagesRef = useRef<(HTMLImageElement | null)[]>([]);

const goToSlide = useCallback(
(index: number) => {
if (isTransitioning) return;

setIsTransitioning(true);

const imagesLength = images?.length ?? 0;
const nextIndex =
imagesLength > 0 ? (index + imagesLength) % imagesLength : 0;
const currentImage = imagesRef.current[currentIndex];
const nextImage = imagesRef.current[nextIndex];

if (currentImage && nextImage) {
gsap.to(currentImage, {
opacity: 0,
duration: 0.5,
ease: "power2.out",
});

gsap.fromTo(
nextImage,
{ opacity: 0, scale: 1.05 },
{
opacity: 1,
scale: 1,
duration: 0.8,
ease: "power2.out",
onComplete: () => {
setIsTransitioning(false);
},
}
);
}

setCurrentIndex(nextIndex);
},
[currentIndex, images?.length, isTransitioning]
);

const nextSlide = useCallback(() => {
goToSlide(currentIndex + 1);
}, [currentIndex, goToSlide]);

const prevSlide = useCallback(() => {
goToSlide(currentIndex - 1);
}, [currentIndex, goToSlide]);

const startAutoPlay = useCallback(() => {
if (timerRef.current) clearInterval(timerRef.current);

timerRef.current = window.setInterval(() => {
if (isPlaying) {
nextSlide();
}
}, autoPlayInterval);
}, [autoPlayInterval, isPlaying, nextSlide]);

const pauseAutoPlay = useCallback(() => {
if (pauseOnHover) {
setIsPlaying(false);
}
}, [pauseOnHover]);

const resumeAutoPlay = useCallback(() => {
if (pauseOnHover) {
setIsPlaying(true);
}
}, [pauseOnHover]);

const handleKeyDown = useCallback(
(e: KeyboardEvent) => {
if (e.key === "ArrowLeft") {
prevSlide();
} else if (e.key === "ArrowRight") {
nextSlide();
}
},
[nextSlide, prevSlide]
);

useEffect(() => {
startAutoPlay();
window.addEventListener("keydown", handleKeyDown);

return () => {
if (timerRef.current) clearInterval(timerRef.current);
window.removeEventListener("keydown", handleKeyDown);
};
}, [startAutoPlay, handleKeyDown]);

const setupImageRefs = (index: number) => (el: HTMLImageElement | null) => {
imagesRef.current[index] = el;
};

return {
currentIndex,
currentImage: (images ?? [])[currentIndex],
nextSlide,
prevSlide,
goToSlide,
isPlaying,
pauseAutoPlay,
resumeAutoPlay,
setupImageRefs,
sliderRef,
totalSlides: images?.length,
};
};