티스토리 뷰

react

React, 노마드 코더 강의 / 영화 사이트 만들면서 어려웠던 부분들 5가지 , 후기

YG - 96년생 , 강아지 있음, 개발자 희망 2021. 12. 24. 03:37

어려웠던 부분 5가지

  1. 데이터 페이지 1,2,3 합쳐서 보여주기
  2. tsx 반복 사용
  3. 검색 query string 사용
  4. youtube api 사용
  5. 리액트 컴포넌트 데이터 방식에 따라 prop을 설정하여 재사용하기

React, 노매드 코더 강의//  영화 사이트 만들면서 어려웠던 부분들 5가지 , 후기

깃허브 주소

 

https://github.com/Gilpop8663/reactmaster

 

GitHub - Gilpop8663/reactmaster: reactmaster

reactmaster. Contribute to Gilpop8663/reactmaster development by creating an account on GitHub.

github.com

 

 

 

1.20개의 데이터가 나오는 API 호출 후 여러 개의 데이터 Array로 묶어서 한 번에 보여주기

  const upcommingData: IMovie[] = [];
 
  const upcommingPage1 = useQuery<IGetVideosProps>(
    ["movies", "upcomming1"],
    () => getUpcommingData(1)
  );
  const upcommingPage2 = useQuery<IGetVideosProps>(
    ["movies", "upcomming2"],
    () => getUpcommingData(2)
  );
  const upcommingPage3 = useQuery<IGetVideosProps>(
    ["movies", "upcomming3"],
    () => getUpcommingData(3)
  );
  
  upcommingPage1.data?.results.map((item) => upcommingData.push(item));
  upcommingPage2.data?.results.map((item) => upcommingData.push(item));
  upcommingPage3.data?.results.map((item) => upcommingData.push(item));
  
  //API
  
  export function getUpcommingData(page: number) {
  return fetch(
    `
   ${BASE_URL}/movie/upcoming?api_key=${API_KEY}&language=en-US&page=${page}`
  ).then((response) => response.json());
}

영화 데이터를 useQuery로 api 호출하는데 api 제공하는 사이트에서 데이터를 1페이지마다 20개씩밖에 안보 내줬고 다른 사람들이 질문한 것에 제공하는 사람들이 더 많은 데이터를 보여주고 싶다면 어레이를 만들어서 보여주라고 하여서 코드를 생각했습니다.

 

그리고 페이지가 정상적으로 작동되려면 데이터를 모두 호출한 뒤에 페이지가 나와야 하므로 아래처럼 맨 마지막 데이터의 길이를 if 문으로 조건을 걸어주었습니다

 

  return (
    <Wrapper>
      {upcommingData.length < 58 ? (
        <Loader>Loading...</Loader>
      ) : (
        <>
          {nowPage1.data?.results[0] && (
            <BannerScreen videoData={nowPage1.data} isWhat="movie" />
          )}

 

2.. tsx 컴포넌트 순환 재사용

 

function ClickMovie({
  bigVideoMatch,
  isWhat,
  videoData,
  search,
  keyword,
  unqKey,
}: IClickMovie) {

...
code
//
          <>
            {similarData.data?.results &&
              clicked &&
              (similarMovieMatch ||
              (locationMovie?.params?.movieId
                ? locationMovie?.params?.movieId === isSearch
                : false) ? (
                <ClickMovie
                  unqKey={unqKey}
                  key={clickedData?.id + "az40"}
                  bigVideoMatch={
                    similarMovieMatch ? similarMovieMatch : locationMovie
                  }
                  videoData={similarData.data?.results}
                  isWhat={"movie"}
                  search={search}
                  keyword={keyword ? keyword : undefined}
                />
              ) : (
                similarData.data?.results &&
                clicked &&
                (similarTvMatch ||
                  (locationTv?.params?.tvId
                    ? locationTv?.params?.tvId === isSearch
                    : false)) && (
                  <ClickMovie
                    unqKey={unqKey}
                    key={clickedData?.id + "az41"}
                    bigVideoMatch={similarTvMatch ? similarTvMatch : locationTv}
                    videoData={similarData.data?.results}
                    isWhat={"tv"}
                    search={search}
                    keyword={keyword ? keyword : undefined}
                  />
                )
              ))}
          </>

같은 컴포넌트를 재사용하는 것을 처음 해보았는데 데이터의 형식만 갖춰준다면 정상적으로 작동한다는 것을 알게 되었습니다.

 

영화 디테일 스크린

 

비슷한 콘텐츠

영화를 눌렀을때 DETAIL 한 정보를 보여주는 컴포넌트였엇고 다시 밑에 비슷한 콘텐츠들을 보여주는 형식이었습니다.

 

제가 원한 것은 비슷한 콘텐츠를 클릭하였을 때 다시 디테일한 정보를 보여주고 또 다른 비슷한 콘텐츠를 보여주고 싶었었습니다.

 

비슷한 콘텐츠를 클릭하였을 때 제대로 나오는 모습

 

3. query string 사용

Query String 쿼리 스트링이란?

 

  • URL, 매개 변수 1 및 매개 변수 2는 수신 DataPage에 있는 매개 변수의 이름입니다.
  • [@field:fieldname1]과 [@field:fieldname2]는 데이터 페이지에 의해 동적으로 기록될 변수 파라미터입니다.
  • 각 전체 쿼리 문자열은 매개 변수 이름과 매개 변수 값(전달되는 값)으로 구성됩니다.
  • "?"는 쿼리 문자열의 시작을 나타내며 "&"은 각 필드 이름/매개 변수 값 쌍을 구분하는 데 사용됩니다.

 

저는 검색창에서 디테일 무비로 갔을 때 url에 무비 아이디 값도 넣고 싶었습니다.

spider을 검색하였을 때의 url
spider 검색된 것중 클릭한 tv id
spider 검색된 것 중 movie 아이디

    const location = useLocation();
  
  let keyword = new URLSearchParams(location.search).get("keyword");
  const onBoxClicked = (id: number) => {
    //console.log(id);
    if (!search) {
      if (isWhat === "movie") {
        history.push(`/movies/${id}`);
      } else if (isWhat === "tv") {
        history.push(`/tv/${id}`);
      }
    } else if (search) {
      if (isWhat === "movie") {
        history.push(`/search?keyword=${keyword}&movies=${id}`);
      } else if (isWhat === "tv") {
        history.push(`/search?keyword=${keyword}&tv=${id}`);
      }
    }
  };

따라서 useLocation을 사용하여 현재 어떤 url에 있는지 확인한 후 keyword 값을 저장하고 movie 혹은 tv에 keyword=${keyword}  & movie 혹은 tv = 아이디 값을 url로 사용자를 이동시켰습니다.

 

 

4. youtube api를 이용하여 마우스를 올렸을 때 자동재생을 하고 싶었습니다.

  const mouseEnter = (event: any) => {
    setOver(true);
  };


{detailVideo ? (
                    <BigCover
                      key={clickedData.id + "az3"}
                      onMouseEnter={mouseEnter}
                      src={
                        over
                          ? `https://www.youtube.com/embed/${detailVideo?.key}?autoplay=1&mute=0&controls=0&loop=1&start=0&playlist=${detailVideo?.key}&cc_lang_pref=ko&cc_load_policy=1&modestbranding=1`
                          : ""
                      }
                      allow="autoplay"
                      frameBorder={0}
                      userWidth={window.innerWidth}
                      bgPhoto={makeImageHelper(
                        clickedData.backdrop_path
                          ? clickedData.backdrop_path
                          : clickedData.poster_path
                          ? clickedData.poster_path
                          : ""
                      )}
                    ></BigCover>
                  ) : (
                    <BigCover
                      key={clickedData.id + "az4"}
                      userWidth={window.innerWidth}
                      bgPhoto={makeImageHelper(
                        clickedData.backdrop_path
                          ? clickedData.backdrop_path
                          : clickedData.poster_path
                          ? clickedData.poster_path
                          : ""
                      )}
                    ></BigCover>
                  )}

디테일 비디오가 있을 때 비디오를 재생시키고 mouseEnter가 되었을 때 over 가 true가 되며 over가 true일 때  youtube api를 활성화시켰습니다. 그리고 사용자가 들어왔을 때 api를 호출하느라 데이터가 제대로 안 나올 수 있으므로 디테일 비디오가 없다면 props에서 받은 clikedData의 포스터 사진을 먼저 보여주도록 하였습니다.

 

그리고 youtube api에서 autoplay가 되지 않았는데 그 이유는 유튜브에서 사용자의 데이터를 무분별하게 소진한다고 크롬에서 autoplay 기능을 막았습니다 예외적으로 api 파라미터 기능 중 mute=0을 한다면 autoplay가 되는데 그 이유는 잘 모르겠다고 인터넷에 많이 나와 있었습니다.

 

그렇지만 검색을 해서 allow="autoplay"를 추가해주니 저는 되었습니다. 그렇지만 배너에서도 비디오 자동재생을 적용했지만 배너에서는 작동을 하지 않았습니다. autoplay를 하려면 youtube api는 적합하지 않은 것 같습니다.

`https://www.youtube.com/embed/${detailVideo?.key}?autoplay=1&mute=0&controls=0&loop=1&start=0&playlist=${detailVideo?.key}&cc_lang_pref=ko&cc_load_policy=1&modestbranding=1`

https://developers.google.com/youtube/player_parameters?hl=ko 

 

YouTube 내장 플레이어 및 플레이어 매개변수  |  YouTube IFrame Player API  |  Google Developers

YouTube 내장 플레이어 및 플레이어 매개변수 개요 이 문서에서는 애플리케이션에 YouTube 플레이어를 삽입하는 방법을 설명하고 YouTube 내장 플레이어에서 사용할 수 있는 매개변수를 정의합니다. I

developers.google.com

 

5. 리액트 컴포넌트 데이터 방식에 따라 prop을 설정하여 재사용하기

 

맨 처음 movie 스크린을 만들 때 nowMovie.tsx라는 Component를 사용하여 만들었었는데 movie를 만든 후 tv 스크린도 만드려고 하니 prop을 사용하지 않아 재사용하기가 어려웠었습니다. 그래서 isWhat이라는 prop을 전달하여 이 데이터가 tv 인지 movie 인지 알려주었습니다. 또한 movieMatch 혹은 tvMatch라는 useRouteMatch를 사용하여 url 주소 형식이 이것과 맞는지 확인하였습니다. 

 

      const bigMovieMatch = useRouteMatch<{ movieId?: string }>(
    !search ? `/movies/:movieId` : "undefined"
  );

  const bigTvMatch = useRouteMatch<{ tvId?: string }>(
    !search ? `/tv/:tvId` : "undefined"
  );

    
    {(locationMovie.params.movieId
        ? locationMovie.params.movieId?.length >= 1
        : false || bigMovieMatch) &&
        isWhat === "movie" && (
          <ClickMovie
            key={"xvcmds"}
            bigVideoMatch={bigMovieMatch ? bigMovieMatch : locationMovie}
            videoData={videoData}
            search={search}
            isWhat="movie"
            keyword={keyword ? keyword : undefined}
            unqKey={unqKey}
          />
        )}
      {(locationTv.params.tvId
        ? locationTv.params.tvId?.length >= 1
        : false || bigTvMatch) &&
        isWhat === "tv" && (
          <ClickMovie
            key={"xvcmdsss"}
            bigVideoMatch={bigTvMatch ? bigTvMatch : locationTv}
            videoData={videoData}
            search={search}
            isWhat="tv"
            keyword={keyword ? keyword : undefined}
            unqKey={unqKey}
          />
        )}

그리고는 App에서 Route path에 [] 배열 형식으로 복수의 path들을 전달하여 사용자가 부드럽게 이동할 수 있도록 하였습니다

function App() {
  return (
    <>
      <Helmet>
        <link
          rel="stylesheet"
          href="https://use.fontawesome.com/releases/v5.15.4/css/all.css"
          integrity="sha384-DyZ88mC6Up2uqS4h/KRgHuoeGwBcD4Ng9SiP4dIRy0EXTlnuz47vAwmeGwVChigm"
          crossOrigin="anonymous"
        />
      </Helmet>
      <Router>
        <Header />
        <Switch>
          <Route path={["/search"]}>
            <Search />
          </Route>
          <Route path={["/tv", "/tv/:tvid"]}>
            <Tv />
          </Route>
          <Route path={["/", "/movies/:movieId"]}>
            <Home />
          </Route>
        </Switch>
      </Router>
    </>
  );
}

재사용하는 컴포넌트 interface와 props 들입니다.

 

interface INowProps {
  videoData: IMovie[];
  sliderTitle?: string;
  search?: string;
  isWhat: string;
  unqKey: string;
}

function NowMovies({
  videoData,
  sliderTitle,
  search,
  isWhat,
  unqKey,
}: INowProps) {

 

앞으로는 어디 어디에 재사용할지 생각을 하고 미리 props 들을 사용하여 여러 번 사용할 수 있도록 하려고 합니다.

 

만들어 본 후기

 

재사용할 수 있는 컴포넌트를 생각해보는 기회가 되었고 , query string에 대해 알게 되었습니다. 그리고 호출한 Api 데이터를 어떻게 다뤄야 할지와 두 개의 비슷하지만 다른 데이터를 typescript에서 오류를 일으키지 않고 interface를 사용하는 방법 등을 배우게 되었습니다. 사이트를 만들면서 실력이 크게 늘은 것 같습니다.
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함