Skip to content

[6주차] IPX 김민서 & 남기림 과제 제출합니다.#15

Open
GirimNam wants to merge 119 commits into
CEOS-Developers:masterfrom
CEOS-FRONT:master
Open

[6주차] IPX 김민서 & 남기림 과제 제출합니다.#15
GirimNam wants to merge 119 commits into
CEOS-Developers:masterfrom
CEOS-FRONT:master

Conversation

@GirimNam

@GirimNam GirimNam commented May 9, 2026

Copy link
Copy Markdown

girimNam and others added 30 commits May 1, 2026 13:27
minsxo and others added 26 commits May 8, 2026 15:11
[REFACTOR] 홈 화면 렌더링 최적화 및 UI 개선
[FEAT] 상세 페이지 구현
Dev- 상세 페이지 및 화면 UI 최적화 master로 merge
feat: 검색페이지에서 상세페이지로의 연결 추가
[FEAT] 검색 페이지 구현
[CHORE] 컴포넌트 디테일 수정
[CHORE] migrate from npm to pnpm
[CHORE] npm -> pnpm 변경
chore: Webpack에서 TurboPack으로 마이그레이션 적용
Comment thread components/DetailInfo.tsx
fontSize: "12px",
fontWeight: 400,
lineHeight: "135%",
letterSpacing: "-0.24px",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

global.css에서 토큰 불러오는 게 앞으로도 훨씬 편하실거예요~~!!

Comment thread app/home/page.tsx
<MovieRow title="US TV Shows" medias={usTVShows.results} />
<div className="flex flex-col gap-6 mt-4">
<Suspense fallback={<RowSkeleton />}>
<AsyncMovieRow title="Popular on Netflix" fetcher={fetchPopular} />

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

다른 분 리뷰에도 달았던 내용인데요, const로 title과 fetcher, slice, large를 분리하고, 이미 props에 slice?와 large? 타입을 잘 정의해주셨다 보니 상수 배열 내의 요소를 map함수로 뿌리고 관리하면 훨씬 간결한 코드가 될 수 있겠다는 생각을 했습니다.

Comment thread app/home/page.tsx
return <div className="w-full h-[415px] bg-neutral-900 animate-pulse" />;
}

function RowSkeleton({ large }: { large?: boolean }) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

skeleton을 그 스켈레톤이 들어갈 컴포넌트와 동일한 디렉터리에 보관하는 게(혹은 skeletons폴더에서 components폴더와 같은 트리를 만들어서) 좋은 컨벤션이라고 하더라구요. 같은 코드 안에 작성하다 보면 너무 길어질 수 있으니 다른 파일로 이동을 권장드립니다.!!


const handleChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
const q = e.target.value;
setQuery(q);

@YJ0623 YJ0623 May 10, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

해당 코드에서는 타자를 하나하나 칠 때마다 전부 setQuery가 호출되어 비효율이 발생합니다. 예를 들어 '세오스'를 검색한다면 [ㅅ, 세, 세ㅇ, 세오, 세오ㅅ, 세오스] 가 전부 호출되고, 만약 이 코드가 api연동으로 연결된다면 '세오ㅅ' 검색 결과가 '세오스'보다 늦게 도착하면 검색 결과도 안 나올 수 있어요. 따라서 debounce함수(useEffect와 setTimeout함수의 조합)을 만들어야 할 것 같습니다.
나중에 프로젝트를 진행하실 때에도 사용자로부터 입력받아 그 입력을 CRUD하는 경우가 많을 텐데요, 방어 로직 구현(ex: 디바운스 함수 등)을 꼭 구현하셨으면 합니다~~

@yiyoonseo yiyoonseo left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

과제 수고 많으셨습니다 😊😍

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

svg 아이콘을 사용하는 방법 중에 svgr 태그도 있으니 참고해보세요!

svgr태그

Comment thread components/HeroBanner.tsx
}, 3000);
return () => clearInterval(interval);
}, [medias.length]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

media.length보다 media자체가 의존성 배열에 있는 게 더 좋아보입니다 !

Comment thread components/MovieCard.tsx

if (!media?.poster_path) {
return <div className={`${sizeClass} rounded-[2px] bg-white shrink-0`} />;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

bg-white 보다는 로고나 아이콘이 포함된 스켈레톤 형식도 고려해보시면 좋을 것 같습니다!

Comment thread app/search/page.tsx
Comment on lines +40 to +45
if (page === 1 || results.length > 0) return;
fetchTopSearches(page).then((data) => {
setTopSearches((prev) => [...prev, ...data.results]);
setHasMore(data.page < data.total_pages);
});
}, [page]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

6주차 과제하시느라 고생많으셨습니당!!

앱 실행 결과, 검색 결과를 지운 뒤 Top Searches로 돌아올 때 기존 pagination 상태가 초기화되지 않아 동일한 Top Searches 데이터가 다시 추가되면서 중복 렌더링되는 것 같습니다.

검색 모드에서 Top Searches 모드로 전환될 때 page/topSearches/hasMore 상태를 초기화하거나, append 전에 중복 id를 제거 처리하면 더 안정적일 것 같습니다!

Comment thread app/home/page.tsx
<BottomNav />
</main>
);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

홈 화면을 HeroBanner, Previews, ContinueWatching, MovieRow로 나누고 각 섹션을 Suspense로 감싼 구조가 좋아 보입니다. 페이지 구성 요소가 잘 보이는 것 같네용!

/>
<Image src="/icons/icon-x.svg" alt="x" width={16} height={16} />
</header>
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

오른쪽 X 아이콘이 현재는 장식 이미지처럼 보여서, 검색어 삭제 기능을 위해서는 button으로 감싸고 aria-label을 추가하면 좋을 것 같아요!

<section className="px-4 py-3">
<h2 className="text-heading2 text-white mb-3 antialiased">
Continue Watching for Girim Nam
</h2>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Continue Watching for Girim Nam이 하드코딩되어 있어서 재사용성이 조금 떨어질 수 있을 것 같습니다. 사용자 이름을 prop으로 받으면 더 좋을 것 같네용!

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.

6 participants