![[인프런 워밍업 클럽 Full-Stack 3기] 3주차 발자국 - Netflix 클론코딩](https://cdn.inflearn.com/public/files/blogs/7a1d4805-37a9-4388-bf91-9374e871f686/inflearn.jpg)
[인프런 워밍업 클럽 Full-Stack 3기] 3주차 발자국 - Netflix 클론코딩
이번주는 Netflix 클론코딩에 관한 내용이었다. Netflix 클론코딩이라던지 무한스크롤 구현이라던지 하는 내용은 이전에도 다른 강의에서 자주 나왔던 항목이어서 그런지 들을 때 좀 가볍게 들었던 것 같다. 다음 주에 있는 인스타그램 클론코딩의 강의+과제 볼륨이 거의 2주치가 되어서 이번주는 쉬어가는 듯 가볍게 듣고 다음 챕터 강의에 집중하려했다.
이번 강의의 핵심은 supabase table에서 데이터 가져오기, 무한 스크롤 구현, SEO 최적화하기였다.
수강 내용
Section 5. Netflix 클론코딩 - 영화검색 서비스 제작하기
이번 챕터에선 Netflix 클론코딩을했다. 어느 때와 마찬가지로 tmdb
에서 데이터를 가져와 영화를 뿌려주고, 해당 영화에 대한 정보를 보여주는 것이었다. 기술 스택은 지난번과 마찬가지로 Next.js, tailwind css를 기반으로했고 이번 프로젝트에서는 특히 상태관리가 필요해 zustand
라이브러리를 선택했다. 강의에서는 recoil
을 사용했지만 리코일의경우 Next.js 15버전과 호환이 잘 되지 않기도 하고 평소에 가벼운 zustand
를 자주 사용해서 해당 라이브러리로 상태관리를 진행했다.
영화 목록 전체 불러오기
우선 영화 데이터는 강의에서 준비해서 supabase 테이블에 모두 넣고 해당 테이블의 데이터들을 모두 불러오는 코드를 작성했다.
const { data, error } = await supabase
.from("movie")
.select("*")
검색 기능 추가하기
위에서 말한 상태관리 라이브러리는 이 검색 기능을 활용하기 위해 사용한다. Header
컴포넌트에 있는 SearchInput
에서 검색을 하면 다른 곳에서도 해당 검색어를 사용하기 위해 검색어를 전역 변수로 지정했다.
const { data, error } = await supabase
.from("movie")
.select("*")
.like("title", `%${search}%`)
search
키워드를 받아와 supabase table 내 title
컬럼에서 search
키워드가 포함된 항목들을 검색한다. 보면서 느끼는건데 확실히 SQL을 알고있으면 이런 키워드를 이해하는 데 좀 더 쉬운거같단 생각이 든다. table이라 그런지 다 SQL문법 사용하네.. 아무튼 이렇게 하면 supabase table에서도 검색어를 손쉽게 찾을 수 있다.
무한 스크롤 구현
무한 스크롤 구현하는 방법은 매우 다양하다. intersection observer
을 사용한다던지.. 이번 강의에서는 가볍게 tanstack-query
와 react-intersection-observer
라이브러리를 통해 무한 스크롤을 구현했다.
const { ref, inView } = useInView({ threshold: 0 });
위는 react-intersection-observer
에서 사용하는 hooks이다.
ref
: 참조할 요소를 지정한다.inView
: 요소를 불러와야 할 경우를true
false
로 판별한다.threshold
: 얼만큼 겹쳤을 경우inView
를 변경할 지 설정한다.
이를 통해 데이터를 불러오는 곳 하단에 <div ref={ref} />
을 작성하면 하단에 닿았을 경우의 트리거가 완성된다. 그리고 그 다음에는 tanstack-query
에 있는 useInfiniteQuery
를 사용한다.
const { data, isFetchingNextPage, isFetching, hasNextPage, fetchNextPage } =
useInfiniteQuery({
initialPageParam: 1,
queryKey: ["movie", keyword],
queryFn: ({ pageParam }) =>
searchMovies({ search: keyword, page: pageParam, pageSize: 12 }),
getNextPageParam: (lastPage, allPages) => {
return lastPage.page ? lastPage.page + 1 : undefined;
},
});
대충 이런식으로.. useQuery
랑은 비슷하지만 hasNextPage
, fetNextPage
등 무한 스크롤 구현에 유용한 기능들이 포함되어있다. 강의를 들으면 깔끔하게 무한 스크롤까지 구현이 가능해진다.
SEO (Next.js generateMetadata)
Next.js에서는 동적으로 metadata를 생성해주는 기능을 제공한다. dynamic page같은 경우 각 페이지별로 메타데이터를 설정해주려고 하면 예를들어 id를 1, 2, 3 이렇게 다 따로 만들 수 없으니 이 때 generateMetadata
를 사용하면 된다.
export async function generateMetadata({ params }: any) {
// Next.js에서는 params를 await 해야 함
const { id } = await params;
const movie = await getMovie(Number(id));
return {
title: movie?.title,
description: movie?.overview,
openGraph: {
images: [movie?.image_url],
},
};
}
강의에서는 Next.js 14 버전이라 별 문제가 없었지만 나는 Next.js 15 버전을 사용해서 params
를 가져올 때 async-await
을 사용해서 가져왔다. 15버전에서 그냥 가져오면 동작은 하지만 에러가 발생한다. 이렇게까지 하면 가볍게 Netflix 클론코딩은 클리어.
미션
3주차미션은 "찜하기" 기능을 구현하는 것이다. 유저 정보도 아직 없고 어떻게 구현할까 하다가 역시 로컬에 저장하는건 localstorage
가 답이다 생각했다. 하지만 Next.js 는 SSR이라 localstorage
를 그저 React처럼 사용한다면 기능이 정상적으로 동작하지 않는다. 따라서 zustand의 persist
를 통해 로컬스토리지에 데이터를 쉽게 사용할 수 있도록 구현했다.
마무리
이번주도 주말까지 무사히 일정을 잘 맞췄다. 몇번 했던 기술들이었지만 한번 더 복습 겸 꼼꼼히 들었다. 예전에는 javascript api 중 intersection observer
을 이용해 무한스크롤을 깡으로 구현했었는데 확실히 라이브러리를 통해 구현하니까 많이 간편했다. 다음 인스타 클론코딩은 거의 2주치 분량이던데 다음주는 진짜 미리미리 듣고 추가미션까지 해낼 수 있도록 노력해야겠다. 마지막 4주차도 화이팅!
댓글을 작성해보세요.