Skip to content

[6주차] Team 이어드림 김영서&이주희 미션 제출합니다. #12

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 16 commits into
base: master
Choose a base branch
from

Conversation

kkys00
Copy link

@kkys00 kkys00 commented May 16, 2025

배포 링크

https://next-netflix-21th.vercel.app/

Key Questions

1. 정적 라우팅(Static Routing)/동적 라우팅(Dynamic Routing)이란?

1-1. 정적 라우팅 (Static Routing)

  • 경로가 정해져 있는 페이지를 만들 때 사용하는 라우팅 방식으로 넥스트에서 폴더 이름을 URL 경로로 하여 구현함
    • ex) /home 페이지 → app/home/page.tsx

1-2. 동적 라우팅 (Dynamic Routing)

  • 경로가 동적으로 변경되는 페이지를 만들 때 사용하는 라우팅 방식으로 경로의 일부를 변수처럼 다룰 수 있는 방식. 넥스트에서 폴더를 [id]처럼 중괄호로 감싸서 구현
    • ex) /movie/1, …, /movie/99 경로 → app/movie/[id]/page.tsx
    • 이 때 props로 { params }가 들어오고, params.id 형태로 접근 가능함.

2. 무한 스크롤과 Intersection Observer API의 특징에 대해 알아봅시다.

1. 무한 스크롤

: 유저의 스크롤 액션에 대해 자동으로 데이터를 더 불러오는 UI 패턴

2. Intersection Observer API 특징

  • Intersection Observer API : 특정 element가 viewport에 포함되고 안되는 시점을 감지할 수 있는 브라우저 API.
  1. 스크롤 이벤트보다 리소스 사용이 적어 효율적이며 성능에 유리함.
  2. const observer = new IntersectionObserver(callback, options)
    • 콜백 함수와 threshold 등 옵션을 인수로 가짐
  3. 콜백 함수는 관찰 대상이 뷰포트에 포함되고 포함되지 않는 변화가 생겼을 때 실행됨
    • entry.isIntersecting을 주로 사용
      • true면 viewport에 보임
      • false면 안 보임
  4. option 중 threshold: observer가 옵저버가 실행되기 위한 타겟의 가시성의 백분율을 의미한다.
    1. threshold: 0 → element가 1px이라도 보이면 isIntersecting = true
    2. threshold: 0.5 → element가 절반이 보여지면 isIntersecting = true
const squares = document.querySelectorAll( "div");

const observer = new IntersectionObserver(
	(squares) => {
		squares.forEach((square) => {
			if (square.isIntersecting) {
				square.target.classList.add("visible");
			} else {
				square.target.classList.remove("visible");
			}
		});
	},
	{
		threshold: 0.5
	}
);
squares.forEach((square) => observer.observe(square));

3. tanstack query의 사용 이유(기존의 상태 관리 라이브러리와는 어떻게 다른지)와 사용 방법(reactJS와 nextJS에서)을 알아봅시다.

참고_heropy.dev

1-1. 사용 이유

  • 서버로부터 데이터 가져오기, 데이터 캐싱, 캐시 제어 등 데이터를 쉽고 효율적으로 관리할 수 있는 라이브러리로 API 호출 중심의 앱이면 TanStack Query가 훨씬 간편하고 효율적이며 간단하다.
  1. 데이터 가져오기 및 캐싱
  2. 동일 요청의 중복 제거
  3. 신선한 데이터 유지
  4. 무한 스크롤, 페이지네이션 등의 성능 최적화
  5. 네트워크 재연결, 요청 실패 등의 자동 갱신

1-2. 기존 상태 관리 라이브러리와의 차이점

항목 기존 상태 관리 (Redux, Zustand 등) TanStack Query
목적 전역 상태 관리 서버 상태 관리 (예: API 호출 결과)
API 캐싱 직접 구현 필요 자동 캐싱 / 리페치
서버 동기화 수동 관리 자동으로 stale 체크, 백그라운드 refetch
로딩/에러 상태 직접 관리 내장 상태 지원 (isLoading, isError)
사용 난이도 설정과 보일러플레이트 많음 간단한 hook 기반 사용

2. 사용 방법 (reactJS와 nextJS에서)

1. Next 프로젝트에서 설치

npm i @tanstack/react-query-next-experimental

2. app/providers.tsx Provider 구성

'use client';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ReactNode, useState } from 'react';

export default function Providers({ children }: { children: ReactNode }) {
  const [client] = useState(() => new QueryClient());

  return <QueryClientProvider client={client}>{children}</QueryClientProvider>;
}

3. 루트 레이아웃 app/layout.tsx 에서 <QueryProvider>를 사용

import Providers from './providers';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  );
}

BeanMouse and others added 16 commits April 29, 2025 23:59
* chore:기본 세팅

Next (eslint 등등), vercel json 파일

* chore: 깃 이슈, PR 템플릿

추가

* chore: 프리커밋 및 커밋 린트 설정

* chore: style md 문구 수정

수정

* chore: commitlint 추가

추가

* chore: 폴더 구조 변화

변화

* chore: 깃 이그노어 추가

* chore: svgr 다운
* chore: tailwind typography 시스템 설정

* chore: svg icon 모음

* feat: 기본 UI, 공통 컴포넌트 구현

* feat: 공통 Play 버튼 컴포넌트 구현

* feat: 홈페이지 상단 네비게이션 구현

* feat: themoviewdb fetching 함수, url 작성

* feat: 디자인 요소 조정

* feat: 이미지 태그 url config 설정

* feat: 원형, 사각형 포스터 컴포넌트 구현

* feat: 횡단 스크롤 컨테이너 구현

* feat: 카테고리별 영화 나열 구현

* feat: 배너 옵션, 설명 컴포넌트 구현

* feat: 홈페이지 구현

* fix: image 태그 경고 수정

* feat: 랜딩 페이지 이동 연결
* chore: tailwind typography 시스템 설정

* chore: svg icon 모음

* feat: 기본 UI, 공통 컴포넌트 구현

* feat: 공통 Play 버튼 컴포넌트 구현

* feat: 홈페이지 상단 네비게이션 구현

* feat: themoviewdb fetching 함수, url 작성

* feat: 디자인 요소 조정

* feat: 이미지 태그 url config 설정

* feat: 원형, 사각형 포스터 컴포넌트 구현

* feat: 횡단 스크롤 컨테이너 구현

* feat: 카테고리별 영화 나열 구현

* feat: 배너 옵션, 설명 컴포넌트 구현

* feat: 홈페이지 구현

* fix: image 태그 경고 수정

* feat: 랜딩 페이지 이동 연결

* feat: 랜딩 페이지 구현

---------

Co-authored-by: leejuhi <[email protected]>
* feat: api 연결

* feat: 페이지 구분

* feat: 상세뷰 추가

* chore: 파일 이동
* chore: tailwind typography 시스템 설정

* chore: svg icon 모음

* feat: 기본 UI, 공통 컴포넌트 구현

* feat: 공통 Play 버튼 컴포넌트 구현

* feat: 홈페이지 상단 네비게이션 구현

* feat: themoviewdb fetching 함수, url 작성

* feat: 디자인 요소 조정

* feat: 이미지 태그 url config 설정

* feat: 원형, 사각형 포스터 컴포넌트 구현

* feat: 횡단 스크롤 컨테이너 구현

* feat: 카테고리별 영화 나열 구현

* feat: 배너 옵션, 설명 컴포넌트 구현

* feat: 홈페이지 구현

* fix: image 태그 경고 수정

* feat: 랜딩 페이지 이동 연결

* feat: 랜딩 페이지 구현

* fix: 배너 영화 순위 표시 조정

* feat: 포스터 클릭 시 상세 페이지로 이동

* fix: 스크롤 오류 수정

* fix: 하단 네비게이션 조정

---------

Co-authored-by: leejuhi <[email protected]>
* feat: 스타일 조정

* fix: 동적 랜더링

* fix: 오타 제거

* chore: jwt에서 다른거 시도

* chore: 구조 변화

변화
* Chore: 초기 세팅 (#1)

* chore:기본 세팅

Next (eslint 등등), vercel json 파일

* chore: 깃 이슈, PR 템플릿

추가

* chore: 프리커밋 및 커밋 린트 설정

* chore: style md 문구 수정

수정

* chore: commitlint 추가

추가

* chore: 폴더 구조 변화

변화

* chore: 깃 이그노어 추가

* chore: svgr 다운

* feat: Home 페이지 구현 (#4)

* chore: tailwind typography 시스템 설정

* chore: svg icon 모음

* feat: 기본 UI, 공통 컴포넌트 구현

* feat: 공통 Play 버튼 컴포넌트 구현

* feat: 홈페이지 상단 네비게이션 구현

* feat: themoviewdb fetching 함수, url 작성

* feat: 디자인 요소 조정

* feat: 이미지 태그 url config 설정

* feat: 원형, 사각형 포스터 컴포넌트 구현

* feat: 횡단 스크롤 컨테이너 구현

* feat: 카테고리별 영화 나열 구현

* feat: 배너 옵션, 설명 컴포넌트 구현

* feat: 홈페이지 구현

* fix: image 태그 경고 수정

* feat: 랜딩 페이지 이동 연결

* feat: Landing 페이지 구현 (#6)

* chore: tailwind typography 시스템 설정

* chore: svg icon 모음

* feat: 기본 UI, 공통 컴포넌트 구현

* feat: 공통 Play 버튼 컴포넌트 구현

* feat: 홈페이지 상단 네비게이션 구현

* feat: themoviewdb fetching 함수, url 작성

* feat: 디자인 요소 조정

* feat: 이미지 태그 url config 설정

* feat: 원형, 사각형 포스터 컴포넌트 구현

* feat: 횡단 스크롤 컨테이너 구현

* feat: 카테고리별 영화 나열 구현

* feat: 배너 옵션, 설명 컴포넌트 구현

* feat: 홈페이지 구현

* fix: image 태그 경고 수정

* feat: 랜딩 페이지 이동 연결

* feat: 랜딩 페이지 구현

---------

Co-authored-by: leejuhi <[email protected]>

* Feature: 검색 페이지 및 상세페이지 기능 구현 (#7)

* feat: api 연결

* feat: 페이지 구분

* feat: 상세뷰 추가

* chore: 파일 이동

* Fix: home (#9)

* chore: tailwind typography 시스템 설정

* chore: svg icon 모음

* feat: 기본 UI, 공통 컴포넌트 구현

* feat: 공통 Play 버튼 컴포넌트 구현

* feat: 홈페이지 상단 네비게이션 구현

* feat: themoviewdb fetching 함수, url 작성

* feat: 디자인 요소 조정

* feat: 이미지 태그 url config 설정

* feat: 원형, 사각형 포스터 컴포넌트 구현

* feat: 횡단 스크롤 컨테이너 구현

* feat: 카테고리별 영화 나열 구현

* feat: 배너 옵션, 설명 컴포넌트 구현

* feat: 홈페이지 구현

* fix: image 태그 경고 수정

* feat: 랜딩 페이지 이동 연결

* feat: 랜딩 페이지 구현

* fix: 배너 영화 순위 표시 조정

* feat: 포스터 클릭 시 상세 페이지로 이동

* fix: 스크롤 오류 수정

* fix: 하단 네비게이션 조정

---------

Co-authored-by: leejuhi <[email protected]>

* feat: 스타일 조정 (#10)

* Chore: 구조 변화 (#11)

* feat: 스타일 조정

* fix: 동적 랜더링

* fix: 오타 제거

* chore: jwt에서 다른거 시도

* chore: 구조 변화

변화

---------

Co-authored-by: Yeongseo Kim <[email protected]>
* feat: 스타일 조정

* fix: 동적 랜더링

* fix: 오타 제거

* chore: jwt에서 다른거 시도

* chore: 구조 변화

변화

* chore: 하드 코딩 대체

* chore: 동적 페이지 변경

* chore: 시도
* Chore: 초기 세팅 (#1)

* chore:기본 세팅

Next (eslint 등등), vercel json 파일

* chore: 깃 이슈, PR 템플릿

추가

* chore: 프리커밋 및 커밋 린트 설정

* chore: style md 문구 수정

수정

* chore: commitlint 추가

추가

* chore: 폴더 구조 변화

변화

* chore: 깃 이그노어 추가

* chore: svgr 다운

* feat: Home 페이지 구현 (#4)

* chore: tailwind typography 시스템 설정

* chore: svg icon 모음

* feat: 기본 UI, 공통 컴포넌트 구현

* feat: 공통 Play 버튼 컴포넌트 구현

* feat: 홈페이지 상단 네비게이션 구현

* feat: themoviewdb fetching 함수, url 작성

* feat: 디자인 요소 조정

* feat: 이미지 태그 url config 설정

* feat: 원형, 사각형 포스터 컴포넌트 구현

* feat: 횡단 스크롤 컨테이너 구현

* feat: 카테고리별 영화 나열 구현

* feat: 배너 옵션, 설명 컴포넌트 구현

* feat: 홈페이지 구현

* fix: image 태그 경고 수정

* feat: 랜딩 페이지 이동 연결

* feat: Landing 페이지 구현 (#6)

* chore: tailwind typography 시스템 설정

* chore: svg icon 모음

* feat: 기본 UI, 공통 컴포넌트 구현

* feat: 공통 Play 버튼 컴포넌트 구현

* feat: 홈페이지 상단 네비게이션 구현

* feat: themoviewdb fetching 함수, url 작성

* feat: 디자인 요소 조정

* feat: 이미지 태그 url config 설정

* feat: 원형, 사각형 포스터 컴포넌트 구현

* feat: 횡단 스크롤 컨테이너 구현

* feat: 카테고리별 영화 나열 구현

* feat: 배너 옵션, 설명 컴포넌트 구현

* feat: 홈페이지 구현

* fix: image 태그 경고 수정

* feat: 랜딩 페이지 이동 연결

* feat: 랜딩 페이지 구현

---------

Co-authored-by: leejuhi <[email protected]>

* Feature: 검색 페이지 및 상세페이지 기능 구현 (#7)

* feat: api 연결

* feat: 페이지 구분

* feat: 상세뷰 추가

* chore: 파일 이동

* Fix: home (#9)

* chore: tailwind typography 시스템 설정

* chore: svg icon 모음

* feat: 기본 UI, 공통 컴포넌트 구현

* feat: 공통 Play 버튼 컴포넌트 구현

* feat: 홈페이지 상단 네비게이션 구현

* feat: themoviewdb fetching 함수, url 작성

* feat: 디자인 요소 조정

* feat: 이미지 태그 url config 설정

* feat: 원형, 사각형 포스터 컴포넌트 구현

* feat: 횡단 스크롤 컨테이너 구현

* feat: 카테고리별 영화 나열 구현

* feat: 배너 옵션, 설명 컴포넌트 구현

* feat: 홈페이지 구현

* fix: image 태그 경고 수정

* feat: 랜딩 페이지 이동 연결

* feat: 랜딩 페이지 구현

* fix: 배너 영화 순위 표시 조정

* feat: 포스터 클릭 시 상세 페이지로 이동

* fix: 스크롤 오류 수정

* fix: 하단 네비게이션 조정

---------

Co-authored-by: leejuhi <[email protected]>

* feat: 스타일 조정 (#10)

* Chore: 구조 변화 (#11)

* feat: 스타일 조정

* fix: 동적 랜더링

* fix: 오타 제거

* chore: jwt에서 다른거 시도

* chore: 구조 변화

변화

* chore: detail view 수정 (#13)

* feat: 스타일 조정

* fix: 동적 랜더링

* fix: 오타 제거

* chore: jwt에서 다른거 시도

* chore: 구조 변화

변화

* chore: 하드 코딩 대체

* chore: 동적 페이지 변경

* chore: 시도

---------

Co-authored-by: Yeongseo Kim <[email protected]>
@kkys00 kkys00 changed the title [6주차] Team 이어드림 김영서&이주희 과제 제출합니다. [6주차] Team 이어드림 김영서&이주희 미션 제출합니다. May 16, 2025
Copy link

@chaeyoungwon chaeyoungwon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

과제하시느라 수고 많으셨습니다!! 홈과 랜딩 페이지 관련해서 코드리뷰 남겨두었습니다 🫠

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BASE_URL처럼 API_KEY도 여러 번 사용되니 상수로 따로 분리해두면 유지보수에 더 좋을 것 같아요 :)

Comment on lines +4 to +15
.font-Headline1 {
font-weight: 700;
font-size: 24px;
line-height: 100%;
letter-spacing: 0px;
}
.font-Headline2 {
font-weight: 700;
font-size: 20px;
line-height: 100%;
letter-spacing: 0px;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네이밍을 headline-*으로 아래 폰트들과 동일하게 통일해주시면 더 보기 좋을 것 같아요!

import Play from "@/assets/play.svg";
const PlayButton = () => {
return (
<button className="bg-[#C4C4C4] flex gap-[15px] items-center justify-center rounded-[5.63px] py-2 w-full cursor-pointer">

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

폰트처럼 자주 쓰이는 색상도 CSS에서 변수로 정리해두고 불러오면 더 관리하기 편할 것 같아요!

className={isActive ? "text-white" : "text-[#8C8787]"}
>
<NavIcon>
{isActive ? <ActiveIcon /> : <Icon />}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

색상만 다른 SVG 파일을 각각 불러오기보단,
하나의 SVG에 fill이나 stroke 속성을 활용해서 색상을 동적으로 바꾸는 방식도 고려해보면 좋을 것 같아요 :)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

홈에서 영화들을 스크롤할 때, 좌우뿐 아니라 위아래로 스크롤했을 때도 좌우로 이동하는 것 같아요
이 부분은 세로 스크롤에는 반응하지 않도록 제한해주시면 더 자연스러울 것 같습니다 :)

Comment on lines +17 to +20
export const metadata: Metadata = {
title: "Deardream Netflix",
description: "Generated by create next app",
};

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

기본 title, description 외에
Open Graph 메타태그도 함께 설정해보시면 좋을 것 같아요.
링크 공유 시 썸네일이나 설명이 더 잘 노출될 수 있습니다!

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 설정을 따로 하신 이유가 있을까요??

const HomeIndicator = () => {
return (
<div className="w-full h-[31.7px] flex justify-center items-end">
<div className="bg-white w-[121.38px] h-[4.53px] rounded-[90.58px] mb-[9px]"></div>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

자식 요소가 없는 경우에는 <div />처럼 self-closing 태그로 작성해주시면 더 깔끔할 것 같습니다!

@@ -0,0 +1,16 @@
@import "tailwindcss";
@import "../styles/typography.css";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

상대 경로 대신 절대 경로(@/styles/typography.css)로 가져오시면 더 보기 좋을 것 같아요!

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

스크린샷 2025-05-19 오후 3 47 29 저도 Figma에서 nav 메뉴 이미지 사이즈와 간격이 조금씩 달라서 신경 썼던 부분이었는데요! 메뉴 라벨들은 우선 일직선상으로 위치하도록 수정해주시면 전체적으로 정돈된 느낌을 줄 수 있을 것 같아요 :)

Copy link

@xseojungx xseojungx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수고하셨습니다!

@@ -0,0 +1,41 @@
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

폰트는 더 상위 요소에서 호출하는게 좋을 것 같습니다!

return (
<html lang="en">
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased bg-[#1E1E1E] `}>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

테일윈드 사용한 클라스 컴포넌트 내부에서 변수를 사용하려면 clsx를 사용해서 cn 유틸 함수 만들어서 사용하면 더 편하게 코드 작성하실 수 있을 것 같아요!

key={movie.id}
className="flex flex-row items-center bg-neutral-700 "
>
<img

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image backdrop_path가 유효하지 않는 사진은 모양이 깨지는 것 같아요!

<div>
<div className="flex w-full h-[52px] bg-neutral-700 text-white items-center p-3 px-3">
<Search width={28} height={28} />
<input

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image ring-0 사용하셔서 클릭시에 파란색 표시 안 뜨게 하는건 어떨까요?

<div
className="w-full min-h-[415px] bg-cover bg-top box-border"
style={{
backgroundImage: `linear-gradient(180deg,rgba(0, 0, 0, 0.45) 0%,rgba(0, 0, 0, 0) 50%, #000000 100%), url(https://image.tmdb.org/t/p/w500${movie.poster_path})`,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기서 div 말고 이미지 태그 사용해서 만든 다음에 src로 경로 넣고 alt 처리까지 하면 좋을 것 같아요! 그리고 그 위에 쉐도우는 따로 올리는 것도 괜찮을 것 같아요

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

지금 svg 파일 컨벤션을 살펴보면 어떤건 카멜 케이스고 어떤건 -로 되어있는데 하나로 통일하시면 좋을 것 같습니다!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants