I have a React component, named ImageSlider, to create a dynamic image slideshow with swipe gesture support and manual navigation controls. I'm using it in an Astro web application. Here's a detailed breakdown of its structure and functionality:
import { useState, useEffect } from 'react';
import { BsChevronCompactLeft, BsChevronCompactRight } from 'react-icons/bs';
import { RxDotFilled } from 'react-icons/rx';
type ImageSliderProps = {
images: String[]; // String of URLs served on ImageKit.io
};
export function ImageSlider({ images }: ImageSliderProps) {
const [currentImageIndex, setCurrentImageIndex] = useState(0);
let xdelta = null;
let ydelta = null;
useEffect(() => {
const interval = setInterval(() => {
const isLastImage = currentImageIndex === images.length - 1;
const newIndex = isLastImage ? 0 : currentImageIndex + 1;
setCurrentImageIndex(newIndex);
}, 5000);
return () => clearInterval(interval); // cleanup
}, [currentImageIndex, images.length]);
const handleTouchStart = (e) => {
xdelta = e.touches[0].clientX;
ydelta = e.touches[0].clientY;
}
const handleTouchEnd = (e) => {
const xmove = xdelta !== null ? e.changedTouches[0].clientX - xdelta : 0;
const ymove = ydelta !== null ? e.changedTouches[0].clientY - ydelta : 0;
if (Math.abs(xmove) > Math.abs(ymove)) {
if (xmove > 0) {
handlePreviousImage();
} else {
handleNextImage();
}
}
}
const handleNextImage = () => {
const isLastImage = currentImageIndex === images.length - 1;
const newIndex = isLastImage ? 0 : currentImageIndex + 1;
setCurrentImageIndex(newIndex);
};
const handlePreviousImage = () => {
const isFirstImage = currentImageIndex === 0;
const newIndex = isFirstImage ? images.length - 1 : currentImageIndex - 1;
setCurrentImageIndex(newIndex);
};
const goToImage = (index: number) => {
setCurrentImageIndex(index);
}
return (
<div className='max-w-[1400px] w-full m-auto py-4 px-4 relative group'>
<div
onTouchStart={handleTouchStart}
onTouchEnd={handleTouchEnd}
style={{ backgroundImage: `url(${images[currentImageIndex]})` }}
className='w-full h-64 sm:h-96 md:h-[70vh] lg:h-[80vh] xl:h-[90vh] bg-center bg-contain bg-no-repeat duration-1000'
></div>
<div className='absolute top-1/2 -translate-y-1/2 left-5 text-2xl rounded-full p-2 bg-black/20 text-white cursor-pointer'>
<BsChevronCompactLeft onClick={handlePreviousImage} />
</div>
<div className='absolute top-1/2 -translate-y-1/2 right-5 text-2xl rounded-full p-2 bg-black/20 text-white cursor-pointer'>
<BsChevronCompactRight onClick={handleNextImage} />
</div>
<div className='flex top-4 justify-center py-2'>
{images.map((_image, index) => (
<div
key={index}
onClick={() => goToImage(index)}
className='text-2xl cursor-pointer'
>
<RxDotFilled className={index === currentImageIndex ? 'text-black' : 'text-black/50'} />
</div>
))}
</div>
</div>
);
}
This component is resulting in a low PageSpeed performance score. How do I improve it?