이미지 슬라이더란 말 그대로 여러 이미지들이 슬라이드되는 컴포넌트를 말한다.
먼저 컴포넌트 props로 이미지 URL이 담긴 배열을 받고 그 이미지들을 매핑했다.
const Slider = ({ imgs }) => {
const total = imgs.length;
return (
<div
className={classes.slider}
style={{ width: `${total * 100}%` }}
>
{imgs.map((img, i) => {
return (
<img
key={i}
src={img}
style={{ width: `${100 / total}%` }}
/>
);
})}
</div>
);
};
.slider {
display: flex;
}
.slider img {
aspect-ratio: 16 / 9;
object-fit: cover;
}
나중에 슬라이드 기능을 구현하기 위해서 슬라이더 안에 이미지들을 나누어 넣었다.
나는 이미지 슬라이드 기능을 transform: translateX로 구현했다. 또한 시간 차를 두고 자동으로 이미지가 슬라이드되는 기능은 useRef를 활용해 구현했다.
const [index, setIndex] = useState(1);
const timeoutRef = useRef(null);
const total = imgs.length;
const resetTimeout = () => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
};
useEffect(() => {
resetTimeout();
timeoutRef.current = setTimeout(() => {
setIndex((prevIndex) => (prevIndex === total ? 1 : prevIndex + 1));
}, 2500);
return () => {
resetTimeout();
};
}, [index, total]);
<div
className={classes.slider}
style={{
width: `${total * 100}%`,
transform: `translateX(-${(100 / total) * (index - 1)}%`,
}}
>
{/* 이미지들 */}
</div>
.slider {
transition: transform 0.5s ease-in-out;
}
먼저 useState로 index 변수를 선언해 현재 이미지의 인덱스를 저장하게 했다. 이후 useRef로 timeoutRef을 선언해 ref 안에 이미지 인덱스를 바꿔주는 timeout 함수를 저장하게 했다. 또한 index가 바뀔 때마다 useEffect 함수가 실행되게 만들어 자연스럽게 이미지 슬라이드가 되도록 했다.
원하는 이미지를 찾아갈 수 있도록 네비게이션을 추가했다.
const total = imgs.length;
<div className={classes.container}>
{/* 슬라이더 */}
<nav>
{Array(total)
.fill()
.map((_, i) => (
<button
key={i}
onClick={() => setIndex(i + 1)}
className={index === i + 1 ? classes.current : ""}
/>
))}
</nav>
</div>
.container {
position: relative;
overflow: hidden;
}
.container nav {
position: absolute;
left: 50%;
transform: translateX(-50%);
bottom: 1rem;
display: flex;
gap: 5px;
}
.container nav button {
padding: 0;
width: 0.75rem;
height: 0.75rem;
border-radius: 50%;
}
.current {
background-color: rgba(255, 255, 255, 0.9);
}
먼저 슬라이더와 네비게이션을 감싸는 컨테이너를 만들었다. 네비게이션은 imgs 배열을 매핑했다.
(완성)