배민상회 클론코딩 프로젝트에서 캐러셀 기능 구현을 맡게되었다.
실제 배민상회 처럼 무한 캐러셀을 구현하고 싶었으나 능력안에서 가장 빠르게 만들 수 있는 방법으로 구현하였다.
import React, { useState, useEffect } from 'react';
import './Carousel.scss';
const Carousel = () => {
const [count, setCount] = useState(0);
const nextBtn = () => {
setCount(count => (count < 9 ? count + 1 : (count = 0)));
};
const prevBtn = () => {
setCount(count => (count > 0 ? count - 1 : null));
};
useEffect(() => {
const interval = setTimeout(() => {
nextBtn();
}, 3000);
return () => clearTimeout(interval);
});
return (
<div className="carousel">
<div className="container">
<div
className="images"
style={{ transform: `translateX(${count * -1080}px)` }}
>
<img src="/images/carousel/1.png" />
<img src="/images/carousel/2.png" />
<img src="/images/carousel/3.png" />
<img src="/images/carousel/4.png" />
<img src="/images/carousel/5.png" />
<img src="/images/carousel/6.png" />
<img src="/images/carousel/7.png" />
<img src="/images/carousel/8.png" />
<img src="/images/carousel/9.png" />
<img src="/images/carousel/10.png" />
</div>
</div>
<button className="prev" onClick={prevBtn}>
〈
</button>
<button className="next" onClick={nextBtn}>
〉
</button>
<div className="chapter">
<p>{count + 1} / 10 </p>
</div>
</div>
);
};
export default Carousel;
images
div를 만든다.container
div를 만든다.carousel
div를 만든다.count
useState를 만들어 prev버튼은 -1 next버튼은 +1을 해준다. 계산을 위해 초기값을 0으로 준다.images
에 transform:translateX(${count * -1080}px)
을 줘서 count가 올라가면 x축으로 -1080px(이미지크기) 만큼 이동하게 한다.count
9에서 next함수를 실행하면 count
를 0으로 만들어서 처음 이미지로 넘어간다.(첫 이미지 count는 0이다.)count+1 / 10
으로 최대 이미지는 임으로 정의한다.useEffect
setTimeout을 설정하고 next 버튼을 누르면 setTimeout이 중첩되서 연속적으로 실행되는 문제가 있었다.
count
state를 공유하고 있어서 문제가 발생한다 판다해서 useEffect로 옮기고 clearTimeout으로 cleanUp을 설정해서 setCount
실행으로 리렌더링 시 인자속 setTimeout을 종료 시키고 새로 실행하여 setTimeout 중첩 문제를 해결하였다.
@import '../../styles/variables.scss';
.carousel {
width: 1080px;
position: relative;
.container {
width: 1080px;
height: 303px;
overflow: hidden;
.images {
display: flex;
height: 303px;
transition: transform 0.5s;
img {
width: 1080px;
height: 303px;
&:hover {
transition: 0.3s;
transform: scale(1.05);
}
&:not(hover) {
transition: 0.3s;
}
}
}
}
.prev,
.next {
position: absolute;
top: 140px;
width: 28px;
height: 28px;
border: none;
background-color: transparent;
font-size: 30px;
color: white;
}
.prev {
left: 10px;
}
.next {
right: 10px;
}
.chapter {
@include flex(center, center);
position: absolute;
bottom: 10px;
right: 10px;
width: 61px;
height: 31px;
border-radius: 30px;
background-color: rgba(0, 0, 0, 0.456);
color: white;
font-weight: bold;
}
}
레이아웃 적인 속성이 대부분이여서 이대로 하면 완성 캐러셀 처럼 구현이 가능하다.
Images에 transition: transform 0.5s
로 넘어가는 속도를 조절하였다.
img에 transition: 0.3s; transform: scale(1.05);
로 Img에 마우스를 올리면 img가 일정속도로 커지는 속성을 줬다. 또 &:not(hover) { transition: 0.3s; }
로 Img에 커서를 때면 일정속도로 다시 돌아온다.
2달전 쯤 바닐라JS로 캐러셀을 만든 적이 있는데 리액트로 다시 만들어 보려 하니 많이 막막했다.
하지만 오히려 JS보다 더 간결하게 코드를 작성할 수 있고 더 직관적이다고 느꼈다.
조금 성장한 기분도 들었지만 무한 캐러셀을 구현할 시간이 부족해 많이 아쉽다.