🎁 모든 강의 30% + 무료 강의 선물🎁

[인프런 워밍업 클럽 3기 풀스택] 3주차 발자국

[인프런 워밍업 클럽 3기 풀스택] 3주차 발자국

학습 내용

이번 주에는 Netflix 프로젝트 클론코딩을 진행했다. 영화 목록 페이지 및 검색 기능과 개별 영화 상세페이지를 구현했다.

  • supabase에서 영화 테이블을 만들고, 준비된 csv 파일로 바로 영화 데이터를 추가

  • header에서 입력한 검색어를 다른 컴포넌트에서 사용하기 위해 Recoil 사용

  • dynamic routing으로 개별 영화 상세페이지 구현

  • 영화 목록을 보여줄 때 무한스크롤 적용

    • react-intersection-observer 라이브러리를 사용해, 보이지 않는 태그를 심어놓고 감지

    • react-query의 useQuery 대신 무한스크롤을 쉽게 구현할 수 있는 useInfiniteQuery 이용

  • 상세페이지의 동적 meta tag 생성을 위해 generateMetadata() 사용해 SEO 작업

imageimage

 

미션

Netflix Clone 프로젝트에 “찜하기” 기능을 추가하세요.

공용 즐겨찾기 기능을 구현하고, 찜한 영화를 리스트 최상단에 보이도록 정렬했다. 찜한 영화 리스트를 가져와서 별도의 찜 목록 페이지에서 보여주는 방법도 고려해볼 수 있을 것 같다.

  • movie 테이블에 bool 타입의 bookmarked column을 추가하고 초기값은 FALSE로 설정


    image

  • searchMovies()에서 order()로 정렬 기준을 추가해 찜한 영화부터 보이도록 하고 다중 정렬하여 찜한 영화 중에서도 id 순서대로 정렬되도록 작성

      const { data, error } = await supabase
        .from("movie")
        .select("*")
        .like("title", `%${search}%`)
        .order("bookmarked", { ascending: false })
        .order("id", { ascending: true })
        .range((page - 1) * pageSize, page * pageSize - 1);
    
  • 북마크 버튼을 누르면 북마크 상태가 반대로 바뀔 수 있도록 Server Action 작성

    export async function updateBookmark(id, status) {
      const supabase = await createServerSupabaseClient();
    
      const { error } = await supabase
        .from("movie")
        .update({ bookmarked: !status }) // 현재 상태 반대로 변경
        .eq("id", id);
    
      handleError(error);
    
      return !status;
    }
    
  • movie-card에서 북마크 mutation을 작성해 updateBookmark()를 실행하고 성공하면 화면이 바로 업데이트되도록 함

    const updateBookmarkMutation = useMutation({
        mutationFn: () => updateBookmark(movie.id, movie.bookmarked),
        onSuccess: () => {
          queryClient.invalidateQueries({ queryKey: ["movie"] });
        },
      });
    
  • bookmarked 값에 따라 북마크 icon을 다르게 표시하고,
    북마크 클릭 시 mutation을 실행해 해당 영화의 bookmarked 값을 반대로 바꿔줌

    return (
        ...
          {/* Bookmark 부분 */}
          <i
            onClick={() => updateBookmarkMutation.mutate()}
            className={`text-yellow-600 drop-shadow-md absolute flex items-center justify-center p-2 text-2xl top-2 right-2 z-20 ${
              movie.bookmarked ? "fa-solid fa-bookmark" : "fa-regular fa-bookmark"
            }`}
          ></i>
        ...
    )
    

image

 

마무리

이번 주에 배운 기능 중에는 이미 한두 번 다뤄본 내용들도 있었는데, 특히 useInfiniteQuery를 이용해 무한스크롤을 더 편리하게 적용해볼 수 있었던 것 같다(그래도 어려웠다…😅). 중간에 막히는 부분도 있었지만, 자세한 사용법을 찾아보고 강의를 따라가며 무한스크롤 구현 과정을 되짚어볼 수 있었다. Next.js가 알아서 해주는 동적 메타데이터 생성으로 간편하게 SEO 적용하는 방법도 알아갈 수 있었다. 현재 아쉬운 점 중 하나는 찜하기 기능을 적용했을 때 비교적 아래쪽의 영화를 찜하니 모든 영화 데이터를 다시 요청해오느라 북마크 표시가 늦게 반영된다는 것인데, 이번 경험으로 invalidateQueries() 대신 setQueryData() 활용을 고려하는 등 네트워크 요청 최적화의 필요성을 느꼈다. 마지막으로 다음 주가 가장 어려운 부분이 될 것 같지만, 끝까지 완주하는 것을 목표로 최선을 다해보려 한다!

댓글을 작성해보세요.


채널톡 아이콘