상세 컨텐츠

본문 제목

NETFLIX CLONE(React)(2-2) - Slider

React/넷플릭스 클론

by 래모 2022. 7. 28. 19:56

본문

넷플릭스 처럼 영화들의 슬라이더를 보여주자


 

Home에서 Banner만든 밑에 넣어줄 것이다.

원래는 Sliders로 따로 컴포넌트를 만들어서 api 데이터를 넘겨주는 식으로 하고 싶었는데

타입스크립트라서 방법이 너무 까다로움 ㅜ 그래서 실패...

1️⃣ data보여주기

const offset = 6;
...
<Slider>
    <AnimatePresence>  
        <Row>
            {nowPlayingData?.results
            .slice(1)
            .slice(offset * index, offset * index + offset)
            .map((movie) => (
                <Box
                key={movie.id}
                bgPhoto={makeImagePath(movie.backdrop_path, "w500")}
                />
            ))}
        </Row>
    </AnimatePresence>
</Slider >

나중에 넣을 애니메이션을 위해 AnimatePresence로 감싸주고 

slice함수를 이용해준다

Banner에서 이미 첫번째 result의 데이터가 쓰였음으로 그거 제외하고 

한 화면에 6(offset)개의 데이터들만 보이도록 설정한다

 

2️⃣Next 버튼으로 Row 애니메이션 설정

const rowVariants = {
  hidden:{
    x:window.outerWidth + 10,
  },
  visible: {
    x: 0,
  },
  exit:{
    x:-window.outerWidth - 10,
  },
};
...
const incraseIndex = () => {
    if (nowPlayingData) {
        if (leaving) return;
        toggleLeaving();
        const totalMovies = nowPlayingData.results.length - 1;
        const maxIndex = Math.floor(totalMovies / offset) - 1;
        setBack(false);
        setIndex((prev) => (prev === maxIndex ? 0 : prev + 1));
    }
};
const toggleLeaving = () => setLeaving((prev) => !prev);
    
...
<AnimatePresence initial = {false} onExitComplete={toggleLeaving}>
      {/* 맨 처음에는 애니 작동 x */}
    <Row
        variants={rowVariants}
        initial="hidden"
        animate="visible"
        exit="exit"
        transition={{ type: "tween", duration: 1 }}
        key={index}
        >
            {nowPlayingData?.results
            .slice(1)
            .slice(offset * index, offset * index + offset)
            .map((movie) => (
                <Box
                key={movie.id}
                bgPhoto={makeImagePath(movie.backdrop_path, "w500")}
                />
            ))}
    </Row>
    <Next onClick = {incraseIndex} whileHover={{scale:1.2}}> <BiArrowFromLeft/></Next>
</AnimatePresence>   
...

next에 해당하는 버튼을 누르면 다음 영화들 목록으로 넘어가는 애니메이션을 만든다.

onEixtComplete 속성은 버튼을 연속해서 누를시 애니메이션이 이상하게 작동되는 것을 막는다

 

window.outerWidth : 브라우저 전체의 너비
window.outerHeight : 브라우저 전체의 높이
window.innerWidth : 브라우저 화면의 너비
window.innerHeight : 브라우저 화면의 높이

 

현재 6개의 box들이 브라우저 전제의 너비만큼 지정되어 있으므로 window.outerWidth를 이용해서 x값에 대한 애니메이션을 주었다

3️⃣ custom을 이용해 back상태에 따른 애니메이션 효과 만들기

const rowVariants = {
  hidden: (back:boolean)=> ({
    x: back ? -window.outerWidth - 10 :  window.outerWidth + 10,
  }),
  visible: {
    x: 0,
  },
  exit:(back:boolean)=> ( {
    x: back ? window.outerWidth + 10 :  -window.outerWidth - 10,
  }),
};
...
<AnimatePresence custom = {back} initial = {false} onExitComplete={toggleLeaving}>
            {/* 맨 처음에는 애니 작동 x */}
          <Row
              variants={rowVariants}
              initial="hidden"
              animate="visible"
              exit="exit"
              transition={{ type: "tween", duration: 1 }}
              key={index}
              custom = {back}
              >
                  {nowPlayingData?.results
                  .slice(1)
                  .slice(offset * index, offset * index + offset)
                  .map((movie) => (
                      <Box
                      key={movie.id}
                      bgphoto={makeImagePath(movie.backdrop_path, "w500")}
                      />
                  ))}
          </Row>
          <Prev onClick = {increaseIndex} whileHover = {{scale:1.2}} key = "increase"><BiArrowFromRight/></Prev>
          <Next onClick = {decreaseIndex} whileHover = {{scale:1.2}} key = "decrease"><BiArrowFromLeft/></Next>
        </AnimatePresence>

custom을 통해 props를 지정한 애니메이션을 지정해줬다

그러므로 뒤로 가는 애니메이션도 가능!!

 

만들다 보니까 스크롤이 자꾸 눈에 거슬려서 아예 안 보이게 해줬다

스크롤바 안 보이게

body{-ms-overflow-style:none; }
body::-webkit-scrollbar { display:none; }

완성!

 


하나의 슬라이더만 넣는 것이 아니라 api별로 총 4개의 슬라이더를 가져올것이다.

이걸 prop으로 넘겨서 Slider라는 컴포넌트에 따로 만들것이다

 

근데!!! 이걸 하는게 드럽게 오래 걸렸다 원래는 

//Home
...
<Slider data = {nowPlayingData}/>


//Slider
function Slider(data:IGetMoviesResult){
...
}

이런 식으로 넘겼는데 

'{ data: IGetMoviesResult | undefined; }' 형식은 'IntrinsicAttributes & IGetMoviesResult' 형식에 할당할 수 없습니다.'IntrinsicAttributes & IGetMoviesResult' 형식에 'data' 속성이 없습니다

이 오류가 자꾸 떴다................
구글링해보니 비구조화 할당 문법으로 {...nowPlayingData}이런식으로 하면 해결된다고 하길래 썼더니 더 이상한 오류가 떳음 ㅎ

'{ dates?: { maximum: string; minimum: string; } | undefined; results?: IMovie[] | undefined; total_pages?: number | undefined; total_results?: number | undefined; }' 형식은 'IGetMoviesResult' 형식에 할당할 수 없습니다.'dates' 속성의 형식이 호환되지 않습니다.'{ maximum: string; minimum: string; } | undefined' 형식은 '{ maximum: string; minimum: string; }' 형식에 할당할 수 없습니다.'undefined' 형식은 '{ maximum: string; minimum: string; }' 형식에 할당할 수 없습니다.

 

결국 다른 노마드코더 챌린지 우수작품 받으신 분의 코드를 참고해서 이렇게 해결했다

// Home
...
<Slider
title="Now Playing Movies"
data={nowPlayingData?.results ?? []}/>

// Slider
interface SlidersProps {
  title?: string;
  data: IMovie[];
}
function Slider({title, data }: SlidersProps) {
...
}

근데..... 분명 저런 비슷한 형태로 시도를 했을 땐 실패했는데...................뭐 해결됐으니까......

앞으로 object를 prop으로 넘길땐 이 코드 참고해야겠다

암튼 !신나게 데이터 연결해서 완성시켰다

관련글 더보기