인터뷰 방식으로 제작기를 적어보았습니다. :)
A. 유튜브 프로젝트 완료 후 리액트를 더 심도있게 배우기 위해서 프로젝트를 고민하다가, 전세계적으로 많이 사용되고 있는 넷플릭스를 선택했습니다.
전세계에서 운영중인 서비스는 어떤 것이 다를까? 나도 만들 수 있을까? 라는 생각에서 시작해 제작하게 되었습니다.
개인적인 리액트 공부와 강의를 보고 제작하였는데, 강의를 보며 공부한 시간보다 추가적으로 공부한 시간이 더 많았던 프로젝트였습니다.!
A. JavaScript
, TypeScript
, React
를 사용해 만들었습니다.
Github pages
를 사용해 배포했고
npm
, react-query
, React Hook Form
, styled-componenet
, framer motion
라이브러리를 사용했습니다.
A. 크게 나누자면 영화, 시리즈, 검색 메뉴가 있습니다.
React-Query
를 사용하여 themoviedb API 패치하여 정보를 가져오고, 카테고리별로 구분된 영화&시리즈가 출력돼요.
영화의 경우 "현재 상영중인 영화, 평점 높은 영화, 인기있는 영화, 상영 예정인 영화"의 정보를 보실 수 있어요.
시리즈 또한 영화와 동일하게 카테고리를 분류했습니다.
해당 카테고리들은 슬라이드하며 이전, 다음 장으로 넘겨가며 확인하실 수 있구요.
영화 위에 마우스를 올리면 제목이 띄워지고, 영화를 클릭하시면 디테일 정보가 있는 모달창이 띄워집니다.
framer motion 을 사용해서 슬라이더와 모달 간의 자연스러운 애니메이션을 구현했습니다.
검색 페이지는 React-Hook-Form
라이브러리를 사용해서 만들었으며
검색 페이지로 들어가거나 우측 상단의 돋보기모양 아이콘을 클릭해서 검색하시면 됩니다.
검색 후 결과 또한 클릭 시 디테일 정보가 있는 모달 페이지를 보실 수 있습니다.
이제 마우스를 올리면 영화의 제목이 이미지 위에 띄워지고
클릭하면 디테일&크레딧 정보가 있는 모달창이 띄워집니다.
시리즈 페이지도 메인 페이지(movie)와 똑같습니다.
검색창에 '아바타' 를 검색한 뒤 나온 결과입니다.
기존 넷플릭스는 영화, 시리즈 카테고리 구분 없이 한번에 나왔지만 저는 구분해주고 싶었습니다.
검색한 키워드는 좌측 상단에 띄워지고, 영화나 시리즈와 같이 마우스를 올리면 제목이 띄워집니다.
클릭하면 모달창이 띄워지는데, 시리즈 카테고리에서 backdrop_poster
데이터가 많이 없었습니다.
또, 아예 이미지 자체가 없는 경우가 종종 있어서 대체 이미지를 만들어줬습니다.
이는 이미지 경로를 만들어주는 함수에 아래와 같이 추가하였습니다.
const NoImage = require("../assets/images/noimage.png");
/** 이미지 경로 만들어주는 함수 */
export function makeImagePath(id: string, format?: string) {
if (id === "" || id === null || id === undefined) {
return NoImage;
} else {
return `https://image.tmdb.org/t/p/${format ? format : "original"}/${id}`;
}
}
A. 검색 페이지가 가장 어려웠습니다.
검색 후 나온 영화 or 시리즈 중 한 개를 클릭했을 때
이 영화 or 시리즈에 대한 디테일한 정보가 모달로 띄워지게 하고 싶었습니다.
(메인(영화)페이지, 시리즈 페이지와 동일하게)
그래서 내가 클릭한 영화 or 시리즈의 id 값을 받아오고,
출력된 결과에서 내가 클릭한 영화의 id 값과 동일한 id 를 가진 객체의 정보를 불러와야 했는데, 찾고 불러오는 과정에서 많이 해맸던 것 같습니다.
! 첫 번째, 내가 클릭한 영화 or 시리즈의 id 값을 가져오기 위한, id 를 저장하는 공간이 필요했습니다.
const [s_Id, sets_Id] = useState<number>();
이에 state 값으로 저장해 관리하였고, 이제 내가 선택한 부분이 어딘지를 확인하여 콜백함수로 전달받게 하였습니다.
const onIdtarget = (id: number) => {
sets_Id(id);
};
return (
...
<S.RowBox <<- 검색 후 결과들
onClick={() => {
onIdtarget(data.id);
seiresClick(data.id);
}}
! 두 번째, 내가 선택한 id 값의 데이터와 일치하는 id 의 데이터 값을 가져오기.
이 부분에서 가장 많이 고민했습니다.
"내가, 또는 사용자가 클릭한 영화 or 시리즈의 id 와 일치하는 데이터를 찾아내려면 어떻게 해야할까"
useNavigate
를 사용해서, 모달창에 내가 클릭한 영화에 대한 id 값을 보내고 있었으니, .find()
를 쓰면 되었던 문제였습니다.
// - SearchMovie.tsx
function SearchSeries({ tvData, keyword }: ISeriesprops) {
const navigate = useNavigate();
const [s_Id, sets_Id] = useState<number>();
const seiresClick = (tv_id: number) =>
navigate(`/search/tv/${tv_id}?keyword=${keyword}`);
const seiresMatch: PathMatch<string> | null = useMatch(
"/search/tv/:tv_id:keyword"
);
const onIdtarget = (id: number) => {
sets_Id(id);
};
// 내가 클릭한 시리즈의 id 값과 결과 값의 id 중 같은 값 찾아내어 변수로 저장
const Sdata = tvData?.results.find(item => item.id === s_Id);
// 오픈 날짜
const sub_Openday = Sdata?.first_air_date?.substring(0, 4);
return (
...
<S.RowBox <<- 검색 후 결과들
onClick={() => {
onIdtarget(data.id);
seiresClick(data.id);
}}
처음에는 index 값에 접근할 생각을 했던지라 오래 걸렸었고, 제가 작성한 코드를 다시 한번 들여다보게 하는 버릇을 만들게 해주었던 문제였습니다.
흐름을 기억하고 잊지 않는 것이 중요하다는 것을 뼈저리게 느꼈습니다.
A. fetch 가 카테고리마다 호출되다보니 화면이 버벅거리거나 데이터를 불러오는데에 지연시간이 늘어나는 것 같아 개선하고 싶습니다.
또, 반복적으로 쿼리를 가져오는 코드를 작성한다거나,
fetch 된 데이터 관리를 위한 useEffect
코드들도 자주 등장하다보니,
반복적인 작업을 하지 않으려면 어떻게 해야할까? 라고 고민하며 커스텀 훅도 만들어 봤었습니다.
종종 시도해봤지만 아직 어려운 부분이 있어, 디벨롭하진 못했습니다.
하지만 이는 계속 고민해가며 해결할 문제로 안고가며 해결할 것 입니다!
A. React-Query 라이브러리와 fetch 를 사용한 API 호출 및 비동기 처리와 함수형 컴포넌트의 생명주기 처리에 대해 가장 많이 고민하며 공부했었던 프로젝트입니다. useMemo
나 useEffect
등의 hook 에 대해 더 자세히 공부할 수 있었습니다.
이전 react-beautiful-dnd 를 사용하면서도 간단한 코드로 애니메이션을 만들 수 있음에 놀랐는데, framer motion 라이브러리를 사용하면서 신세계를 경험할 수 있었습니다.
TypeScript 를 사용하며 interface
, type
, enum
에 대한 부분도 깊게 공부할 수 있었습니다!
그리고 가장 신세계였던 framer-motion
을 공부하면서 이 라이브러리와 Three.js
를 사용하여 애니메이션이 가득한 화려한 사이트를 만들고 싶다는 상상으로 하루가 즐거웠습니다 :)
A. 제 마음 속 2위를 차지한 차애 프로젝트 입니다.
프레임워크, 여러 라이브러리를 사용하며 배울 수 있었던 점,
애니메이션 라이브러리로 관련한 CSS 를 간단히 만들면서 너무 재밌었던 기억들이 납니다!
어떤 데이터는 보여주고 어떤 데이터는 보여주지말까? 고민했던 과정들도,
이 프로젝트를 시작할 때 다짐했던 부분도 해소할 수 있어 행복한 시간이였습니다.
몇일동안 끙끙대며 고민했던 문제를, 제 손으로 해결했고 또 앞으로 나아갈 수 있다는 점이 정말 행복했습니다!