Skip to content

Conversation

@Tutankhannun
Copy link

@Tutankhannun Tutankhannun commented Nov 8, 2025

구현화면

image image

배포링크

폴더구조

next-netflix-22nd
├─ app
│ ├─ (frame) # 공통 프레임용 그룹 라우트
│ │ ├─ detail
│ │ │ └─ [media]
│ │ │ └─ [id]
│ │ │ └─ page.tsx
│ │ ├─ home
│ │ │ ├─ layout.tsx
│ │ │ └─ page.tsx
│ │ └─ search
│ │ └─ page.tsx
│ │
│ ├─ (splash) #초기 스플레시 이미지
│ │ ├─ layout.tsx
│ │ └─ page.tsx
│ │
│ ├─ api
│ │ └─ tmdb
│ │ └─ top-rated
│ │ └─ route.ts # /api/tmdb/top-rated
│ │
│ ├─ fonts.css
│ ├─ globals.css
│ └─ layout.tsx # 앱 루트 레이아웃

├─ src
│ ├─ components
│ │ ├─ detail
│ │ │ └─ detail.tsx
│ │ ├─ home
│ │ │ ├─ cardrow.tsx
│ │ │ ├─ header.tsx
│ │ │ ├─ hero.tsx
│ │ │ ├─ herooverlay.tsx
│ │ │ ├─ menu.tsx
│ │ │ ├─ previews.tsx
│ │ │ └─ section.tsx
│ │ ├─ landing
│ │ │ └─ BrandSplash.tsx
│ │ ├─ layout
│ │ │ ├─ Footer.tsx
│ │ │ ├─ Header.tsx
│ │ │ └─ MobileTabBar.tsx
│ │ ├─ scroll
│ │ │ └─ scroll.tsx
│ │ └─ search
│ │ ├─ searchbox.tsx
│ │ ├─ searchitem.tsx
│ │ └─ searchresults.tsx
│ │
│ ├─ lib
│ │ └─ tmdb.ts # TMDB fetch/유틸
│ └─ types

├─ public

6주차 회고

👨‍🚀 김윤성

-5주차 때 피드백으로 받은 폴더구조를 참고해 리팩토링을 한 후 6주차 과제를 진행했다.

  • 무한 스크롤을 구현하며 좀 더 웹과 api의 작동 과정을 이해할 수 있었다. 저번 주차 때는 크게 api를 다룰만한 역할이 아니었지만
    이번 주차 때는 api의 어느 데이터를 얼마나 가져오고 언제 요청하는 지 등 다양하게 다뤄보며 공부해 볼 수 있었다.
  • 여전히 깃 협업은 어렵다.. 충돌나는 상황도 힘들지만 충돌이 안나도 문제였다. 서로 다른 폴더에서 작업을 하고 머지를 했을 때 충돌은 안났지만 도리어 이를 정리하는데 시간이 많이 들었다. 좀 더 협업 컨벤션을 엄격하게 잘 만들어야겠다.
  • 상세 페이지를 구현할 때 인자가 promise로 동기 객체처럼 바로 전달 되는데 이를 await을 활용하여 상세 페이지 컴포넌트로 데이터가 잘 전달되게 하였다. 상세 페이지에서 계속 api 정보는 있는데 화면이 뜨지 않았는데 위 방법으로 해결하였다. api흐름과 동기/비동기, promise와 관련된 문법을 더 알아봐야겠다.

👩‍🚀 이채연

  • 파일, 폴더 구조를 명확하게 하는게 얼마나 중요한지 한번 더 느끼게 되었다.
  • 또한 내 스케줄에만 맞추는것이 아니라 협업자도 작업할 시간이 필요하니 스케줄 관리에도 신경을 써야겠다고 생각했다.
  • Next.js에서는 화면 출력 파일이 pages.tsx로 통일되어야한다고 해서 기존에 리액트만 할때와는 또 다른 폴더 구조를 사용해야 할것같다.

Copy link

@Wannys26 Wannys26 left a comment

Choose a reason for hiding this comment

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

과제하시느라 고생 많으셨습니다!!

제가 포크하신 레포지토리도 방문했는데, Issue나 PR 템플릿을 활용하셔서 작업하시면 더 좋을거 같습니다. 이슈, PR 템플릿

그리고 API 함수 작성하고 사용하는 부분에 대해서 찾아보시면 좋겠습니다.
다음 과제도 Next js를 사용하고, 백엔드와 api 연동이 있는걸로 예상되는데,
이전 기수들 PR 보시면서 api관련 코드들을 잘 읽어보시고 잘 협업하실 수 있으면 좋겠습니다!!

Copy link

Choose a reason for hiding this comment

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

피그마 디자인이 의도된게, search 페이지의 검색어가 없는 초기에는 Top Search가 뜨는게 맞지만,
검색 내용은 검색 api 해당 api를 사용하는게 맞습니다..!

해당 api 사용하는 걸로 변경하시고, debounce 처리도 하시면 좋을거 같습니다

'';
const url = `https://api.themoviedb.org/3/${media}/${id}?language=eng-US`;

const res = await fetch(url, {
Copy link

Choose a reason for hiding this comment

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

보통 baseURL이나 엑세스 토큰을 HTTP 헤더에 넣은 기본 함수를 따로 생성하고,
그 기본 함수를 import해와서 API 경로나 쿼리 파라미터 등을 덧붙혀서 다른 API 함수를 생성하는 방식으로 API 관련 파일들을 구성합니다.
API 호출 관련 함수는 src/lib/api 폴더 아래에 정리해두시는게 좋을 거 같습니다.

Copy link

Choose a reason for hiding this comment

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

API 모듈 분리
API를 효율적으로 관리하는 방법
위 사이트의 폴더 구조가 정답은 아니지만 참고하시는 용도로 올려두겠습니다!

Copy link

Choose a reason for hiding this comment

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

확인해보니 tmdb.ts에 tmdbFetch라는 함수로 기본함수를 만들어 놓으셨는데,
tmdb.ts 파일 안에 정의를 하시거나 tmdbFetch함수를 이용하시면 좋을거 같습니다

Copy link

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.

파일이름 Detail.tsx가 더 좋을 거 같아여

@@ -0,0 +1,50 @@
// app/(frame)/detail/[media]/[id]/page.tsx
import Detail from '@components/detail/detail';

Choose a reason for hiding this comment

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

절대경로 이렇게 하면 오류 발생 하나요..?? @/components/detail/Detail 이런식으로 수정해야할 거 같습니다

if (!res.ok) {
throw new Error(`TMDB detail ${media}/${id} ${res.status}`);
}
return res.json();

Choose a reason for hiding this comment

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

axios 라이브러리 적용하면 코드가 더 간단해질 수 있을 거 같아요

export default function SplashLayout({
children,
}: {
children: React.ReactNode;

Choose a reason for hiding this comment

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

import 방식으로 import type { ReactNode } from 'react'; 이게 더 좋을 거 같습니다

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.

협업 컨벤션을 문서로 작성하셨네요👍🏻

Choose a reason for hiding this comment

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

왜 파일명이 hero인가요..? 좀 더 직관적인 방식으로 파일명을 정하는게 좋을 거 같아요..!! 그리고 컴포넌트 이름들이 다 소문자인데.. 대문자로 해서 구분하는 게 좋을 거 같아요

: '/placeholder.png';

return (
<Link href="#">

Choose a reason for hiding this comment

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

서치 페이지에서 영화 목록 누르면 상세페이지로 이동하지 않는데 의도하신건가요..??

Copy link

@sungahChooo sungahChooo left a comment

Choose a reason for hiding this comment

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

코드 잘 봤습니다. 과제 하느라 수고 많으셨어요!!! 👍🏻

Copy link

@jungyungee jungyungee left a comment

Choose a reason for hiding this comment

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

과제하느라 수고 많으셨습니다..!!
잘 보았습니다. 코드와 결과물 보면서 몇 가지 개선할 점들 코멘트 달아보았습니다..!

Comment on lines +8 to +26
async function fetchTmdbDetail(media: 'movie' | 'tv', id: string) {
const token =
process.env.TMDB_ACCESS_TOKEN ||
process.env.NEXT_PUBLIC_TMDB_ACCESS_TOKEN ||
'';
const url = `https://api.themoviedb.org/3/${media}/${id}?language=eng-US`;

const res = await fetch(url, {
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json;charset=utf-8',
},
cache: 'no-store',
});
if (!res.ok) {
throw new Error(`TMDB detail ${media}/${id} ${res.status}`);
}
return res.json();
}

Choose a reason for hiding this comment

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

주완 님이 리뷰남겨주신 것처럼 해당 API 호출은 api 폴더 내에서 함수로 정의해주시면 더 좋을 것 같습니다!

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.

전체적으로 components 내 파일명 규칙을 통일해주면 좋을 것 같습니다.!

: '/placeholder.png';

return (
<Link href="#">

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.

이건 굳이 안넣으셔도 될것 같아요..!

Choose a reason for hiding this comment

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

하단바는 home이 아닌 navigation 등 다른 폴더로 빼는 게 더 좋을 것 같습니다.!

Comment on lines +13 to +15
const [activeMenu, setActiveMenu] = useState<string>('');
const router = useRouter();

Choose a reason for hiding this comment

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

activeMenu가 실제 라우팅과 연동되지 않아서, 주소를 직접쳐서 들어가거나 뒤로가기로 페이지 이동할 경우 지금처럼 메뉴바 상태와 실제 페이지가 맞지 않게 될 수 있습니다.
image

usePathname()을 사용하면 상태를 반영할 수 있으니 이걸 사용하는 것을 추천드립니다..! (저희 코드에서 이렇게 사용했습니다..!)

Comment on lines +64 to +66
activeMenu === key ? 'text-white' : 'text-menu-gray'
} hover:text-white ${clickable ? 'cursor-pointer' : 'cursor-default'}`}
>

Choose a reason for hiding this comment

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

지금은 active된 메뉴와 마우스 hover한 메뉴 둘다 색이 white로 바뀌면서 혼란을 줄 수 있을 것 같습니다. 호버 관련된 건 없애는게 좋을것 같아요..!
image

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.

5 participants