캐러셀(Carousel) 만들기 (4)

Salt·2024년 3월 22일
0

Carousel

목록 보기
4/4

오늘 만들건 Prev, Next 버튼과 useRef를 사용해 현재 몇번째 이미지를 보고 있는지 표시해주는 기능을 만들거다. 시작하기 전에 현재 나는 캐러셀에 20개의 이미지를 보여주고 있는데 이대로 진행할 경우 이미지 순서 표시 기능을 만들었을때 캐러셀 하단이 버튼으로 가득찰텐데 이건 보기 안좋으니 이미지 20개가 아니라 랜덤으로 5개를 뽑아서 보여주는 방식으로 바꾸도록하자.

/** 랜덤으로 n개의 요소를 반환하는 함수 */
function getRandomMovies(array: IMovie[], n: number) {
  return [...array].sort(() => Math.random() - 0.5).slice(0, n);
}

일단 랜덤으로 n개의 요소를 반환하는 함수를 만들고 추가해주자.

const randomMovies = getRandomMovies(movies, 5);
return (
    <SliderContainer>
      <Slider $total={total} $index={index} $transition={carouselTransition}>
        <SlideImage src={makeBgPath(movies[total - 1].backdrop_path)} />
        {randomMovies?.map((movie) => (
          <SlideImage key={movie.id} src={makeBgPath(movie.backdrop_path)} />
        ))}
        <SlideImage src={makeBgPath(movies[0].backdrop_path)} />
      </Slider>
    </SliderContainer>
  );
}

당연하게도 캐러셀이 박살나서 제대로 작동하지 않는다. 그리고 오류를 수정하면서 알게된 사실인데 이렇게 하면 렌더링마다 랜덤배열이 계속 갱신되기 때문에 캐러셀이 뒤죽박죽이 된다.

const [randomMovies] = useState(() => getRandomMovies(movies, 5));

useState 훅을 사용해 랜덤 영화 배열을 생성하도록 바꿔주고 다음과 같이 수정하면 끝.
1. total = movies.length가 아니라 randomMovies.length로 수정
2. 무한 캐러셀을 구현하기 위해 만들었던 앞, 뒤 이미지 movies -> randomMovie로 수정
수정 후 코드는 다음과 같다.

  const [randomMovies] = useState(() => getRandomMovies(movies, 5));
  const total = randomMovies.length;
  
  <Slider $total={total} $index={index} $transition={carouselTransition}>
        <SlideImage src={makeBgPath(randomMovies[total - 1].backdrop_path)} />
        {randomMovies?.map((movie) => (
          <SlideImage key={movie.id} src={makeBgPath(movie.backdrop_path)} />
        ))}
        <SlideImage src={makeBgPath(randomMovies[0].backdrop_path)} />
   </Slider>

이제 버튼을 만들 차례다. prev, next 버튼은 Interval을 만들때 사용했던 로직과 똑같기 때문에 쉽다.

  function setPrevIndex() {
    setIndex((prev) => {
      if (prev === 0) {
        setCarouselTransition("");
        setSeconds(0);
        return total;
      }
      setCarouselTransition(`transform 500ms ease-in-out`);
      setSeconds(3000);
      return prev - 1;
    });
  }

  function setNextIndex() {
    setIndex((prev) => {
      if (prev === total) {
        setCarouselTransition("");
        setSeconds(0);
        return 1;
      }
      setCarouselTransition(`transform 500ms ease-in-out`);
      setSeconds(5000);
      return prev + 1;
    });
  }

순서 표시 기능은 내일..

0개의 댓글