Netfilx Clone #6 API + 무비 슬라이드 만들기

Leesu·2023년 2월 2일
0
post-thumbnail

api - themoviedb


API

  • 우선 apis 폴더를 만들어서,
    그 안에 movie + serires = Movi_Ser_Api.ts 파일을 하나 만들고, 검색 기능 전용인 SearchApi.ts 를 만들었다

  • movie 와 tv(series) api 의 interface가 거의 한 두개 차이로 다 똑같았기 때문에 영화와 TV(시리즈)를 한데 묶음.

  • 그런데 movie 나 tv 둘다 한 개가 아닌 현재 상영중인, 유명한, 상영예정 등인 등등 카테고리가 여러개를 불러와야했다.

  • Movie

    • Nowplaying, Popular, Top Rated, upcoming
  • Tv(Serise)

    • popular, top_rated, on_the_air
  • 고민하다가, fetch 시 Popular 나 upcoming 이 들어가야하는 자리에,
    대신 category 로 변수를 부여하고 useQuery 사용 시 인자에 카테고리 넣어주기로함

// apis/Movi_Ser_Api.ts

interface IResult {  <<<--- 영화와 tv에 공통으로 사용해주었다
  // 공통
  id: number;
  backdrop_path: string;
  overview: string;
  release_date: string;
  poster_path: string;
  vote_average: string;
  // ------ seires 정보
  name: string;
  // ------ movies 정보
  title?: string;
}

export function getMovies(category: string) {
  return fetch(
    `${BASE_PATH}/movie/${category}?api_key=${API_KEY}&language=en-US&page=1`
  ).then(response => {
    return response.json();
  });
}
 .
 .
 .
// -Movie.tsx

function Home() {
  // Nowplaying API
  const { data: now_data, isLoading: now_Loading } = useQuery<IGetResult>(
    ["movies", "now"],
    () => getMovies("now_playing")
  );

  // Popular(Trending Now) API
  const { data: pop_data, isLoading: pop_Loading } = useQuery<IGetResult>(
    ["movies", "popular"],
    () => getMovies("popular")
  );
  .
  .
  .
  

MovieSlider.tsx

  • Routes 폴더 안에 있는 Movie.tsx 에는 배너 + 카테고리별 슬라이더 총 4개가 보여질 예정이므로 카테고리별 슬라이더 제작해주기
  • Coponents/movies/ 폴더 안에 slider 와 모달 창에 띄워질 detail 정보들 넣어줄 것!
  • 그리고 부모 컴포넌트인 Movie.tsx 에서 data, title, category 를 받아오면된다.
// Movie.tsx

 {/* -- 슬라이드 영역 -- */}
          <MovieSlider
            category="now_playing"
            title="Now Playing"
            data={now_data}
          />
          <MovieSlider
            category="top_rated"
            title="High Rated"
            data={top_data}
          />
          <MovieSlider
            category="popular"
            title="Trending Now"
            data={pop_data}
          />
          <MovieSlider category="upcoming" title="Coming soon" data={up_data} />
        </>
// MovieSlider.tsx

const MovieSlider: React.FC<IBannerProps> = React.memo(
  ({ category, data, title }) => {
  
  ...
  
  }
  • useState 를 사용하여 슬라이더에 애니메이션을 넣어줬다.
  • 여기는 좀 ..고전했다능,, 구글의 힘을 많이 받았다 ..ㅎㅎ
  • 그리고 슬라이드가 index 값으로 없어졌다 사라지니, AnimatePresence 도 넣어줬다!
const MovieSlider: React.FC<IBannerProps> = React.memo(
  ({ category, data, title }) => {
    // - 슬라이더 내에 한번에 보여주고싶은 영화의 개수
    const offset = 6;

    // - 슬라이드 다음, 이전으로 넘기기위한 인덱스
    const [index, setIndex] = useState(0);

    // 슬라이드 애니메이션 방향 설정
    const [isNext, setIsNext] = useState(true);

    // - leaving : 슬라이드 내에 이동중인 애니메이션이 끝났는지 확인
    const [leaving, setLeaving] = useState(false);
    const toggleLeaving = () => setLeaving(prev => !prev);
    
   return (
  	  ...
        <H.Slider>
          <H.Slider_Title>{title}</H.Slider_Title>
          <AnimatePresence
            custom={isNext}
            initial={false}
            onExitComplete={toggleLeaving}
          >
            <H.Row
              key={category + index}
              variants={RowVariants}
              initial="hidden"
              animate="visible"
              exit="exit"
              custom={isNext}
              transition={{ type: "tween", duration: 1 }}
            >
              {resultsData &&
                resultsData.map(movie => (
                  <H.RowBox
                    onClick={() => onBoxClicked(movie.id)}
                    key={category + movie.id}
                    variants={BoxHoverVariants}
                    initial="initial"
                    whileHover="hover"
                    transition={{ type: "tween" }}
                    bgphoto={makeImagePath(...)} >
                    <H.RowBox_Info variants={H.infoVariants}>
                      <h4>{movie.title}</h4>
                    </H.RowBox_Info>
                  </H.RowBox>
                ))}
            </H.Row>
          </AnimatePresence>
          <H.prevBtn onClick={prevIndex}>
            <svg xmlns="...">
            </svg>
          </H.prevBtn>
          <H.nextBtn onClick={nextIndex}>
            <svg xmlns="..." />
            </svg>
          </H.nextBtn>
        </H.Slider>

MovieDetail (모달창)

  • 무비 슬라이더에서, 슬라이더를 클릭하면 모달창이 띄워지도록 할 것.
    띄워진 모달창에는 내가 선택한 영화의 디테일 + 크레딧 정보들을 넣어줄 것
  • 그러기 위해 내가 선택한 영화의 id 값을 url 에 담아서, 모달창이 띄워질 url 로 보냄되것쥬?
  const navigate = useNavigate();
  const onBoxClicked = (movieId: number) => {
    navigate(`/movies/${movieId}`);
  };
  const bigMovieMatch: PathMatch<string> | null =
    useMatch("/movies/:movieId");

useNavigatemovieId 값을 담아 보낸 특정 URL 로 이동시킨 뒤에,
그 URL 로 잘 이동되었는지 확인하기 위한 useMatch !

    {/* -- 모달 영역 -- */}
    {bigMovieMatch ? (
      <>
        <MovieDetail
          id={bigMovieMatch.params.movieId!}
          category={category}
        />
      </>
    ) : null}
  • 내가 설정한 URL 로 이동하였다면 모달창을 띄워주게 해줬다.
  • 이제 MovieDetail 페이지도 간단히 만들어보자.
// -MovieDetail.tsx

interface IDetailProps {
  category?: string;
  id: string;
}

function MovieDetail({ category, id }: IDetailProps) {
  const navigate = useNavigate();

  // movie detail API
  const { data: detailData, isLoading: detailLoading } = useQuery<IGetDetail>(
    ["movie", `${category}_detail`],
    () => getMovieDetail(id)
  );

  // movie credit API
  const { data: creditData, isLoading: creditLoading } = useQuery<IGetCredit>(
    ["movie", `${category}_credit`],
    () => getMovieCredit(id)
  );
  • detail 과 credit api 둘다 이렇게 가져와서 쓰면된다! 인자로 값만 넣어주면 끝!
  • const navigate = useNavigate(); 이거는 x 버튼 클릭하면 뒤로가기 되는 기능때문에 넣어놨다.
<M.Poster_prevBtn onClick={() => navigate(-1)}>✕</M.Poster_prevBtn>

이런식으로 사용해줬음.

  • 그리고 디테일 페이지에서 가장 고민을 많이했던 부분인데
{detailData?.genres.slice(0, 3).map((genre, index) => (
    <p id="genrs" key={genre.id}>
      {genre.name}
      {index !== detailData.genres.length - 1 && " · "}
    </p>
  ))}
  • genre. 그러니까 장르가 3개가 안되는 것도 있고 3개가 훌쩍 넘는 것도 있어서 css 가 망가지기 일쑤더라...
  • 그래서 3개로 제한시켰고 마지막 요소 뒤에는 "·" 이 붙지 않도록했다.
  • 모달창에는 !
    특별한 애니메이션은 추가하지 않았기에 빠르게 페이지를 만들 수 있었다! :)
  • tv(series)도 동일한 로직으로 금방 짰다.
  • 혼모노는 검색페이지........ 그때 생각만하면 벌써두렵

완성

아무튼 완성!
넷플릭스랑 최대한 비슷하게 만들고싶어서 엄청 심혈을 기울였다능,,!

profile
기억력 안 좋은 FE 개발자의 메모장

0개의 댓글