티스토리 뷰
React, 노마드 코더 강의 / 영화 사이트 만들면서 어려웠던 부분들 5가지 , 후기
YG - 96년생 , 강아지 있음, 개발자 희망 2021. 12. 24. 03:37어려웠던 부분 5가지
- 데이터 페이지 1,2,3 합쳐서 보여주기
- tsx 반복 사용
- 검색 query string 사용
- youtube api 사용
- 리액트 컴포넌트 데이터 방식에 따라 prop을 설정하여 재사용하기
React, 노매드 코더 강의// 영화 사이트 만들면서 어려웠던 부분들 5가지 , 후기
깃허브 주소
https://github.com/Gilpop8663/reactmaster
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에 무비 아이디 값도 넣고 싶었습니다.
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
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 들을 사용하여 여러 번 사용할 수 있도록 하려고 합니다.
만들어 본 후기
'react' 카테고리의 다른 글
react-redux 설치 및 이용방법 (0) | 2022.02.11 |
---|---|
리액트로 라이브러리 없이 캐러셀 슬라이드 만들기 (0) | 2022.01.25 |
React Query 에 대한 글 (0) | 2021.12.10 |
Recoil 에서 Selector 기능 get, set 사용법 (0) | 2021.12.04 |
Simple form validation with React Hook Form 에 관한 글 (0) | 2021.12.03 |
- Total
- Today
- Yesterday
- 프리온보딩
- TopLayer
- javascript
- 원티드
- CLASS
- 노마드코더
- C언어
- import/order
- createPortal
- 초보
- WSL2
- nodejs
- 노개북
- 윤성우 열혈C프로그래밍
- error
- 위코드
- NextApiRequest
- 우아한테크코스
- React
- 아차산
- NextRequest
- Storybook
- env
- jest
- 프론트앤드
- 북클럽
- nextjs
- electron
- 스토리 북
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |