[toy프로젝트] 라이브러리 없이 캐러셀(Carousel)만들기

lee·2023년 11월 14일
0

모영 프로젝트

목록 보기
6/8

설명

영화관 검색 페이지에 밑에 영화관에서 영화 순위 데이터를 백엔드에서 넘겨주어서 그냥 표시하는 것보다 캐러셀로 이동이 되면 좋겠다는 팀원들의 의견이 있어 추가하기로 하였다.

조건

  1. 자동으로 슬라이드가 되어야 한다.
  2. 앞,뒤 버튼 클릭시 움직여야 한다.
  3. 마우스 오버가 되면 멈추고 아웃되면 다시 움직여야 함.

로직


빨강: Contnet
파랑: ContentCarousel
핑크: 각각의 Slide
노랑: 버튼

코드

코드 설명(순서)

1. 현재 인덱스를 확인하기 위한 state와 전체 인덱스 state만들기

// carousel.tsx

// 캐러셀 필요한 useState들
  // 현재 인덱스 확인하기 => 박스 한개에 나는 5개가 들어가니깐 한칸씩 움직인다고 했을때면 10 - 5
  const [slideIndex, setSlideIndex] = useState(0);
  // 인덱스가 몇개까지 일지 => 이걸로 마지막 판별 => 10 - 5 값인 5를 초깃값으로 설정
  const [totalIndex, setTotalIndex] = useState(5);

2. 버튼 추가하여 onClick함수 만들기

// 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>

3. 자동으로 넘어가는 함수(hook) 만들기

//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;

setInterval을 사용 하지 않은 이유는 찾아보기도 하고 실행도 했는데 원하는 대로 되지 않아서 따로 훅을 만들어 사용했습니다.

도움 받은 블로그

// carousel.tsx

// 인터벌 hook
  useInterval(
    // 첫번째 인자는 콜백함수를 받기 때문에
    // 현재 인덱스와 전체 인덱스가 같다면 === 끝이다.
    // 그렇기 때문에 현재 인덱스를 다시 0으로 변경해주고 
    // 아니라면 +1을 계속 해주는 로직
    () => {
      if (slideIndex === totalIndex) {
        setSlideIndex(0);
      } else {
        setSlideIndex(slideIndex + 1);
      }
    },
    carouselRunning ? 2000 : null,
  );

import하여 사용한다.

4. 마우스 오버/아웃시 멈추기

// 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>

위에 사용된 인터벌 훅 두번째 인자를 통해 마우스 오버/아웃시 멈출수 있는데, 상태를 한개 만들어 ture와 false를 각각 나누어 주면 된다.

5. CSS-Styled-Components

// 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;
`;
profile
초보 코딩

0개의 댓글