원티드 프리온보딩 프런트엔드에 지원하며 과제로 캐러셀을 만들어봤다.
결과는 불합격했다. 변명을 하자면 남은 시간이 이틀이었고 네비 바를 꼼꼼하게 만들다가 시간이 부족했다. 솔직히 내 실력이 충분했다면 충분히 완성할 수 있지 않았을까? 그래서 캐러셀을 다시 정리해보기로 했다.
조건
- 라이브러리 없이 만들기
- 버튼 클릭 시 넘어가기
- 무한 캐러셀로 마지막 이미지일 경우 다시 처음으로 돌아가기(첫 이미지일 경우 마지막 이미지로)
- 5초 뒤에 자동으로 이미지 넘기기
- 한 번에 이미지가 3개씩 보이도록
무한으로 이미지를 넘기기 위한 방식은 다음과 같다.
나는 총 9장의 이미지를 사용하고 양 옆의 이미지가 조금씩 보여야 하므로 앞쪽에 8,9번 이미지를 추가해주고 뒤쪽에 1,2번 이미지를 추가해준다.
여기 1번 이미지에서 왼쪽으로 버튼을 누르면
왼쪽 9번 이미지로 이동 후 0.5초 뒤에 실제 9번 위치로 이동시켜주면 된다!
<div className="slider__container">
<div className="slider" ref={slideRef}>
{sliderData.map((slider, index) => {
return (
<div className="slider__box" key={index}>
<img
className="slider__img"
src={slider.img}
alt="slider__image"
/>
</div>
);
})}
</div>
<button className="left__btn" onClick={prevSlide}>
<
</button>
<button className="right__btn" onClick={nextSlide}>
>
</button>
</div>
여기서 slider__container에는 overflow: hidden;을 넣어 넘치는 부분은 보여주지 않도록 한다.
slider는 이미지 사이즈*개수(패딩을 포함해 1094*13=14092) 값으로 width를 지정해준다.
slider__box는 float: left;로 왼쪽에 붙여준다.
.slider__container {
position: relative;
overflow: hidden;
}
.slider {
width: 14092px;
}
.slider__box {
display: table;
padding: 0 12px;
float: left;
}
curIndex는 첫 번째 이미지 위치인 2로 speed는 500으로 초기값을 주었다.
const IMG_WIDTH = 1084;
const length = sliderData.length;
const sliderRef = useRef(null);
const [curIndex, setCurIndex] = useState(2);
const [speed, setSpeed] = useState(500);
const prevSlide = () => {
if (curIndex > 0) {
setSpeed(500);
setCurIndex((curIndex) => curIndex - 1);
}
if (curIndex === 2) {
setTimeout(() => {
setSpeed(0);
setCurIndex(10);
}, 500);
}
};
const nextSlide = useCallback(() => {
if (curIndex < length - 2) {
setSpeed(500);
setCurIndex((curIndex) => curIndex + 1);
}
if (curIndex === 10) {
setTimeout(() => {
setSpeed(0);
setCurIndex(2);
}, 500);
}
}, [curIndex, length]);
useEffect(() => {
sliderRef.current.style.transform = `translate3d( -${
curIndex * IMG_WIDTH - 214
}px, 0, 0)`;
sliderRef.current.style.transition = `${speed}ms ease`;
const timer = setInterval(nextSlide, 5000);
return () => clearInterval(timer);
}, [curIndex, speed, nextSlide]);
이전 버튼을 클릭 시 curIndex를 1씩 빼주고 500ms로 앞으로 한 칸씩 이동한다.
만약 현재 curIndex의 값이 2라면 즉 첫 번째 이미지라면
1. curIndex를 1로 이동
2. 0.5초 후 speed 0ms로 curIndex 10으로 이동시킨다. (사용자가 눈치채지 못하도록)
다음 버튼을 클릭 시 curIndex를 1씩 더해주고 500ms로 뒤로 한 칸씩 이동한다.
만약 현재 curIndex의 값이 10이라면 즉 마지막 이미지라면
1. curIndex를 11로 이동
2. 0.5초 후 speed 0ms로 curIndex 2으로 이동시킨다. (사용자가 눈치채지 못하도록)
useEffect에서 sliderRef로 스타일에 접근하여 위치 값을 변경해준다.
5초 뒤 자동으로 슬라이드를 넘기기 위해
setInterval함수 안에 nextSlide를 넣어 5초마다 이동하게 한다.
useEffect 배열(deps)에는 curIndex, speed, nextSlide를 넣어주어 이 값이 업데이트될 때마다 실행될 수 있도록 한다.
이때 nextSlide를 useCallback으로 감싸주어 배열(deps)의 값이 바뀔 때만 실행되도록 한다. 불필요한 함수 생성 및 실행을 막을 수 있다.
전체 소스는 아래에서 볼 수 있다.
https://github.com/y-solb/wanted_clone
더 좋은 방법이나 개선할 점이 있다면 댓글로 부탁드립니다!🧐
참고 자료
'IT > React' 카테고리의 다른 글
[TIL] React에 ESLint와 Prettier 설정 (0) | 2022.02.28 |
---|---|
Infinite scroll 구현하기 (0) | 2022.02.16 |
nodejs 버전 변경 (0) | 2022.02.14 |
React에서 resize (0) | 2022.02.13 |
React.FC 장단점 (0) | 2021.11.06 |