빨강: Contnet
파랑: ContentCarousel
핑크: 각각의 Slide
노랑: 버튼
// carousel.tsx
// 캐러셀 필요한 useState들
// 현재 인덱스 확인하기 => 박스 한개에 나는 5개가 들어가니깐 한칸씩 움직인다고 했을때면 10 - 5
const [slideIndex, setSlideIndex] = useState(0);
// 인덱스가 몇개까지 일지 => 이걸로 마지막 판별 => 10 - 5 값인 5를 초깃값으로 설정
const [totalIndex, setTotalIndex] = useState(5);
// carousel.tsx
// 이전 버튼 => 현재 슬라이드가 0이 아니라면 -1 해주기 0이 되면 아무것도 실행이 안됨.
const prevSlide = () => {
if (slideIndex !== 0) {
setSlideIndex(slideIndex - 1);
}
};
// 다음 버튼 => 전체 인덱스와 현재 인덱스가 같지 않다면 +1 해주기 같다면 끝이라는 뜻이기때문에 아무것도 실행이 안됨.
const nextSlide = () => {
if (totalIndex !== slideIndex) {
setSlideIndex(slideIndex + 1);
}
};
// 이전 버튼
<ButtonDiv onClick={prevSlide}>
<button>
<BsFillArrowLeftSquareFill />
</button>
</ButtonDiv>
...
...
...
// 다음 버튼
<ButtonDiv onClick={nextSlide}>
<button>
<BsFillArrowRightSquareFill />
</button>
</ButtonDiv>
//useInterval.ts
import { useRef, useEffect, useCallback } from 'react';
function useInterval(callback, delay) {
const savedCallback = useRef();
const intervalIdRef = useRef();
useEffect(() => {
savedCallback.current = callback;
}, [callback]);
useEffect(() => {
function tick() {
savedCallback.current();
}
if (delay !== null) {
intervalIdRef.current = setInterval(tick, delay);
}
const id = intervalIdRef.current;
return () => {
clearInterval(id);
};
}, [delay]);
}
export default useInterval;
// carousel.tsx
// 인터벌 hook
useInterval(
// 첫번째 인자는 콜백함수를 받기 때문에
// 현재 인덱스와 전체 인덱스가 같다면 === 끝이다.
// 그렇기 때문에 현재 인덱스를 다시 0으로 변경해주고
// 아니라면 +1을 계속 해주는 로직
() => {
if (slideIndex === totalIndex) {
setSlideIndex(0);
} else {
setSlideIndex(slideIndex + 1);
}
},
carouselRunning ? 2000 : null,
);
// carousel.tsx
// 마우스 오버,아웃 판단 스태이트 => 마우스 오버시 캐러셀 멈추기 아웃시 다시 실행
const [carouselRunning, setCarouselRunning] = useState(true);
// 인터벌 hook
useInterval(
...
...
...
// 두번째 인자는 시간을 받는데 만약 carouselRunning이 true라면 2000(2초)마다 실행이 되고 false라면 null을 넘겨주어 멈추게 된다.
, carouselRunning ? 2000 : null,
);
<Slide key={el.rank} $slideIndex={slideIndex}>
<MovieBox
....
....
// 마우스 오버 핸들러
onMouseOver={() => {
setCarouselRunning(false);
}}
// 마우스 아웃 핸들러
onMouseOut={() => {
setCarouselRunning(true);
}}
>
....
....
</MovieBox>
</Slide>
// Styled-Components
// overflow로 width을 넘거가게 되면 hidden속성을 주었다.
const ContentCarousel = styled.ul`
display: flex;
list-style: none;
overflow: hidden;
width: 1032px;
`;
// styled-components는 좋은점이 props로 값을 넘겨줄 수 있다는 점인데,
// 인덱스 값을 넘겨줌으로 transform에 translateX속성(가로)주어서 현재 인덱스가
// 변경이 될 때마다 값이 동적으로 바뀌어 움직이게 된다.
// 100%마다 각 Slide한개 씩이라고 생각하면 된다.
// 자연스러운 동작을 위해 transition을 주었다.
const Slide = styled.li<ImgProps>`
/* 위치 이동 && 애니메이션 */
transform: translateX(-${props => props.$slideIndex * 100}%);
transition: all 0.5s ease-in-out;
`;