Skip to content
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

[6주차] BariBari 미션 제출합니다. #16

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

Conversation

YelynnOh
Copy link

@YelynnOh YelynnOh commented May 19, 2023

서론

안녕하세요 바리바리팀 오예린, 최민주입니다!😇
이번 과제는 처음부터 끝까지 정말로 에러와 싸웠던 한 주였네요..😱
reactQuery, SSR 등 새로운 개념들을 코드에 녹여보려고 한 것이 수 많은 물음표와 에러의 원인이 된 것 같아요.
그래도 그 덕에 민주도 저도 강해질 수 있었던 것 같습니다..^-^ 고생 많았다고 제 파트너에게 박수를 쳐주고 싶네요!🥂

배포 링크

감격

구현 내용

필수 요건

  • 상세 페이지와 검색 페이지를 구현한다.

  • 상세 페이지는 동적 라우팅을 이용해 구현한다.

  • 검색 페이지는 실시간 키워드 검색으로 구현한다.

  • 피그마 디자인을 그대로 구현한다.

  • SSR을 적용해서 구현한다.

    • 서치 페이지에서 데이터를 먼저 가져오기 위해서 SSR을 위한 파일을 작성을 했습니다. 이때 getServerSideProps()를 활용을 했는데, 제 컴퓨터에서만 실행이 되고 다른 분들의 컴퓨터에서는 실행이 되지 않는 아주 요상한 문제가 발생하더라구요..!
    • 그리고 심지어 배포도 되지 않았습니다 (...)
    • 알고보니 Nextjs 13 버전의 경우 아직 베타 버전이기 때문에, getStaticProps, getInitialProps, getServerSideProps 가 지원이 안된다는 글을 찾았습니다. 대신 fetch 사용을 권장한다고 합니다. 참고
    • 그래서 조금 아쉽지만 결국 SSR 관련 파일은 삭제를 하고, 클라이언트에서만 데이터 불러오는 방식으로 구현을 했습니다.
  • 결론: 배포할 때는 Nextjs 13 버전 쓰는 것을 지양하세요..! 고생 많이 하는 것 같아요..!😇👍

  • Open api를 사용해서 데이터 패칭을 진행한다.

선택 사항

  • 검색 페이지 무한스크롤을 구현한다.

    • 배포하기 전 코드에서 무한 스크롤이 적용이 됐다가 안됐다가 했는데, 배포한 결과를 보니 무한 스크롤 기능이 작동을 하지 않네요..! ㅜㅠ ... 이건 차차 수정을 해보도록 하겠습니다..
    • 구현되었습니다! 제가 div ref={bottom} 위치를 화면 아래로 내렸더니 먹히는 것 같아요..! 야호
    • image
  • Netflix 로고가 뜬 후에 프로필을 선택할 수 있는 화면을 구현하였습니다.

  • 프로필을 누르고 Home 화면으로 넘어가면 Navigation 바 오른쪽에 해당 프로필이 작고 귀엽게 뜹니다!🎵

Key Questions

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

  • 정적 라우팅
  1. 라우팅 경로와 해당 경로에 대한 페이지를 미리 사전에 정의를 해주는 방식임.
  2. Nextjs 13 에서는 app 경로를 기준으로 app/about 폴더 안에 page.tsx가 있을 경우, page.tsx에 대한 경로가 자동으로 생성이 됨.
  • 동적 라우팅
  1. Nextjs에서 동적 라우팅은 폴더 이름을 [대괄호] 로 묶어주는 것으로 가능함.
  2. 예를 들어, 우리 과제에서는 app/Home/[id]/page.tsx 경로로 영화 세부 페이지를 볼 수 있음.

2. 성능 최적화를 위해 사용한 방법

  • Home page에서 PosterBox 컴포넌트 활용

    • 지난주 과제에서는 홈 화면에서 뜨는 원 이미지와 사각형 이미지를 각각 다른 컴포넌트로 처리를 했는데, 이번주에는 PosterBox 라는 하나의 컴포넌트로 처리해 성능을 개선하였습니다.
    • <PosterBox key={movie.id} id={movie.id} circle = {false} title = {movie.title} image = {`https://image.tmdb.org/t/p/original${movie.poster_path}`} description= {movie.overview}/> 에서 circle 불리언 값을 props로 전달해 보여지는 이미지의 모습을 원 혹은 사각형으로 결정하였습니다.
  • Next Image 컴포넌트 활용

    • 이미지 최적화를 위해 Nextjs에서 제공하는 Image 컴포넌트를 활용했습니다. Navigation 컴포넌트, Header 컴포넌트에서 활용하신 것을 확인할 수 있습니다.
    • 공식 문서
    • Nextjs Image 장단점

YelynnOh and others added 30 commits May 9, 2023 21:55
라우팅한 거 보냅니다,,,
[fix] styled-components 삭제
Lottie Loading 페이지 만듬요
[feat] 홈 화면 스타일링 및 전체 구조 수정
[feat] Header 컴포넌트 생성
�Recoil 선언까지 해놨어용!!
[feat] Top Rated 완성
[fix] TitleText 함수명 수정
프리뷰랑 toprated까지 완성
[feat] header randomimage 불러오기 성공
mainpage 전체 구조 수정
[feat] nowPlaying, popularMovies 구현
Copy link

@westofsky westofsky left a comment

Choose a reason for hiding this comment

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

안녕하세요 Repick 팀 배성준입니다!
이번 과제 정말 고생하셨습니다~~ Data를 가져오는 방식에 대해 고민을 더 했던 이번주였습니다,.
무한 스크롤도 구현하려고 많이 노력하신 것 같은데 꼭 성공하시길 바라요!!!
몇가지 관련해서 comment 달았습니다 참고해주시면 좋을 것 같아요


const Container = styled.div<{circle: boolean;}>`
width: 110px;
height: ${(props) => (props.circle ? '105px' : '163px')};

Choose a reason for hiding this comment

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

scroll 내리다 보면 2px정도 밀리는 형상이 있어서 감싸는 div에는 굳이 height를 주지 않아도 될 것 같아요!

Suggested change
height: ${(props) => (props.circle ? '105px' : '163px')};


return (

<div className={styles.container}>

Choose a reason for hiding this comment

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

container을 맨 마지막으로 내리면 position : fixed로 되어있는 Navigation과 겹쳐 보이지 않는데 전체를 감싸는 container에 padding-bottom : 60px; 정도 주면 좋을 것 같아요

Comment on lines +40 to +46
<body>
<Providers>
<RecoilRoot>
{children}
</RecoilRoot>
</Providers>
</body>

Choose a reason for hiding this comment

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

대부분의 page에서 Navigation 사용하는 것 같은데 매 페이지 하단에 <Navigation/>을 주기 보다 Layout에서 전체적으로 준 다음 Navigation Component에서 페이지 확장성을 위해 '/''/ProfilePage'에 예외를 주는 건 어떨까요 ??

Copy link
Author

Choose a reason for hiding this comment

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

오 그것도 좋은 방법인 것 같네요!!👍👍 감사합니다!:D

Comment on lines 178 to 189
const MovieTitle = styled.div`
font-style: normal;
font-weight: 400;
font-size: 14.7222px;
line-height: 30px;
letter-spacing: 0.751111px;
padding-left: 15px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: white;
`

Choose a reason for hiding this comment

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

MovieTitle이 길어지면
image
옆 Play 버튼이 작아질 수 있어서 MovieTitle이 정해진 영역만 차지하도록 width를 주는 건 어떨까요 ?

Suggested change
const MovieTitle = styled.div`
font-style: normal;
font-weight: 400;
font-size: 14.7222px;
line-height: 30px;
letter-spacing: 0.751111px;
padding-left: 15px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: white;
`
const MovieTitle = styled.div`
font-style: normal;
font-weight: 400;
font-size: 14.7222px;
line-height: 30px;
letter-spacing: 0.751111px;
padding-left: 15px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: white;
width : 180px;
`

Copy link
Author

Choose a reason for hiding this comment

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

헛 제가 무한스크롤 기능 구현에 초점을 맞추느라 디자인 부분을 세세하게 체크하지 못했네요;-; 코드에 반영하도록 하겠습니다! 감사합니다🙌

<div key={result.id}>
{result.id ? (
<InnerList>
<Img src={`https://image.tmdb.org/t/p/original${result.poster_path}`} alt={result.title} />

Choose a reason for hiding this comment

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

result의 id는 있지만 poster가 없을 수 있어서

Suggested change
<Img src={`https://image.tmdb.org/t/p/original${result.poster_path}`} alt={result.title} />
{result.poster_path === null ? ( (
<Img src="/error.jpg" alt={result.title} />
) : (
<Img src={`https://image.tmdb.org/t/p/original${result.poster_path}`} alt={result.title} />
)}

로 예외처리 해주는 게 좋을 것 같아요!

Copy link
Author

Choose a reason for hiding this comment

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

아하 어쩐지 종종 poster_path 불러오는데 엑박이 뜨는 부분들이 있더라구요..! 예외 처리하면 해결이 되겠네요 감사합니다~! Repick 팀에서는 넷플릭스 배경으로 하셨던데 잘 보았습니닷 ㅎㅎ

Comment on lines +22 to +39
return (
<div className={styles.container} align-items="center">
<Title>넷플릭스를 시청할 프로필을 선택하세요.</Title>
<BigProfileBox>
{userInfo.map((user, index) => (
<Link href={`/Home`} as={`/Home`} key={user.userId}>
<ProfileBox onClick = {() => handleUser(user.userId, user.userName)}>
<ProfileImage src= {`/image/${user.userName}.jpeg`}/>
<ProfileName>{user.userName}</ProfileName>
</ProfileBox>
</Link>
))}

</BigProfileBox>
</div>

);
}

Choose a reason for hiding this comment

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

프로필 페이지 선택해서 띄워주는 디테일 너무 귀엽네요

Comment on lines +28 to +36
<MovieSlider>
{
previewMovies.map((movie) =>{
return (
<PosterBox key={movie.id} id={movie.id} circle = {true} title = {movie.title} image = {`https://image.tmdb.org/t/p/original${movie.poster_path}`} description= {movie.overview}/>
);
},
)}
</MovieSlider>

Choose a reason for hiding this comment

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

중복되는 code인 만큼 따로 component로 관리해도 좋을 것 같아요!

@@ -0,0 +1,38 @@
"use client"

Choose a reason for hiding this comment

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

여기서 혹시 use client를 사용하신 이유가 있을까요 ??

);
});
})}
<div ref={bottom} />

Choose a reason for hiding this comment

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

저희랑 ref 사용하시는 건 같은 데 저희는 참고 여기 참고했습니다! 한번 확인해보셔요~~

Copy link
Author

Choose a reason for hiding this comment

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

참고자료 덕에 제 에러의 원인을 명확히 파악할 수 있었네요 감사합니닷~!!

Copy link

@oyatplum oyatplum left a comment

Choose a reason for hiding this comment

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

안녕하세요~ 6주차 코드 리뷰 파트너 Repick의 이예지입니다!!😆
이번 주도 수고 많으셨어요ㅎㅎ!!

query 사용하신 부분과 사용자 선택하는 기능 추가해주신 것 보고 많은 고민을 하신 게 느껴졌습니다👍🏻👍🏻
두 분 모두 게더에서 에러와 전쟁하시는 것 보고 자극을 많이 받았던 것 같습니다!!ㅎㅎ

넷플릭스 과제 마무리 하시느라 고생하셨고 스터디 때 봬요~💗

Comment on lines +15 to +16
<NavItem icon = "Coming Soon"/>
<NavItem icon = "Downloads"/>

Choose a reason for hiding this comment

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

Coming SoonDownloads 에 해당하는 페이지가 없어서 404 에러가 뜨는 것 같아요!!
NavItem 컴포넌트에서 예외 처리를 해주거나 다른 컴포넌트로 관리해도 좋을 것 같아요ㅎㅎ👍🏻

Comment on lines +17 to +19
<ProfileBox>
<Profile src = {`/image/${user.userName}.jpeg`}/>
</ProfileBox>

Choose a reason for hiding this comment

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

새로 고침하면 Profile 이미지가 엑박으로 뜨는 것 같아용ㅠㅠ

Comment on lines +24 to +35
<Title>넷플릭스를 시청할 프로필을 선택하세요.</Title>
<BigProfileBox>
{userInfo.map((user, index) => (
<Link href={`/Home`} as={`/Home`} key={user.userId}>
<ProfileBox onClick = {() => handleUser(user.userId, user.userName)}>
<ProfileImage src= {`/image/${user.userName}.jpeg`}/>
<ProfileName>{user.userName}</ProfileName>
</ProfileBox>
</Link>
))}

</BigProfileBox>

Choose a reason for hiding this comment

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

프로필 선택 기능 추가한 아이디어!! 너무 좋네요!!! 굿👍🏻👍🏻

Copy link

Choose a reason for hiding this comment

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

너무 귀여워요,,,

Copy link

Choose a reason for hiding this comment

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

프로필 선택 기능 너무 좋은 것 같아요~!!👍


const fetchSearchData = async ({ queryKey, pageParam = 1 }: { queryKey: [string]; pageParam?: number | undefined }) => {
const searchInput = queryKey[0];
const apiKey = "4a427cc6585f047c91a2fa3483fb8d31";

Choose a reason for hiding this comment

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

apiKey와 같은 변수는 .env 파일로 관리해보는 게 어떨까요ㅎㅎ?

Copy link
Author

Choose a reason for hiding this comment

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

네넵 맞아요 .env 파일에 상수로 처리를 해줬었는데.. 눈물 나는 vercel 배포 에러들 중 apiKey를 읽어오지 못하는 에러가 있더라구요..! 그래서 부득이하게 마지막에 apiKey 변수를 직접 입력해줄 수 밖에 없었습니다 ;-;
참고로 Nextjs에서 .env 파일에 상수를 선언하고, 파일 전역에서 사용하고 싶을 경우 NEXT_PUBLIC_~~ 이런 식으로 선언을 해주면 된다고 합니다!

Copy link

@sujinRo sujinRo left a comment

Choose a reason for hiding this comment

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

안녕하세요! 이번 주 과제 리뷰를 맡은 댄서포트, 노수진입니다!

추가된 기능들을 보고 정말 열심히 과제하셨다는 것을 느낄 수 있었습니다.
저희 팀과 같은 문제를 겪으시면서 정말 많이 고생하신 것 같아요...ㅜ

정말 수고하셨고, 곧 스터디에서 봬요!😊

<TitleBox>{movieInform[0].title}</TitleBox>
<DesBox>{movieInform[0].description}</DesBox>
</div>
);
Copy link

Choose a reason for hiding this comment

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

recoil을 이용해서 상세페이지 정보를 받아오셨군요,,! 저는 useSearchParams()를 이용해 query를 받아오는 방식으로 정보를 받아왔는데, 그럴 경우 주소가 너무 길게 나오게 되더라구요,, recoil을 통해 하는 방법을 생각 못했는데,, 알아갑니다,,!

Comment on lines +24 to +35
<Title>넷플릭스를 시청할 프로필을 선택하세요.</Title>
<BigProfileBox>
{userInfo.map((user, index) => (
<Link href={`/Home`} as={`/Home`} key={user.userId}>
<ProfileBox onClick = {() => handleUser(user.userId, user.userName)}>
<ProfileImage src= {`/image/${user.userName}.jpeg`}/>
<ProfileName>{user.userName}</ProfileName>
</ProfileBox>
</Link>
))}

</BigProfileBox>
Copy link

Choose a reason for hiding this comment

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

너무 귀여워요,,,

Copy link

@paya17 paya17 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 +14 to +17
const topRatedMovies = useRecoilValue(topRatedMoviesRecoil);
const popularMovies = useRecoilValue(popularMoviesRecoil);
const previewMovies = useRecoilValue(previewMoviesRecoil);
const nowPlayingMovies = useRecoilValue(nowPlayingMoviesRecoil);
Copy link

Choose a reason for hiding this comment

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

api 데이터를 전역상태로 관리하신 이유가 있으신가요??

Comment on lines +54 to +55
<PosterBox key={movie.id} id={movie.id} circle = {false} title = {movie.title} image = {`https://image.tmdb.org/t/p/original${movie.poster_path}`} description= {movie.overview}/>
);
Copy link

Choose a reason for hiding this comment

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

https://image.tmdb.org/t/p/original 가 계속 반복되니까 상수로 따로 빼주시면 좋을 것 같아요!

Comment on lines +24 to +35
<Title>넷플릭스를 시청할 프로필을 선택하세요.</Title>
<BigProfileBox>
{userInfo.map((user, index) => (
<Link href={`/Home`} as={`/Home`} key={user.userId}>
<ProfileBox onClick = {() => handleUser(user.userId, user.userName)}>
<ProfileImage src= {`/image/${user.userName}.jpeg`}/>
<ProfileName>{user.userName}</ProfileName>
</ProfileBox>
</Link>
))}

</BigProfileBox>
Copy link

Choose a reason for hiding this comment

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

프로필 선택 기능 너무 좋은 것 같아요~!!👍

{!isQueryLoading && !isDataLoading && !isFetching && data && data.pages && (
<List>
{searchResults.map((movie) => {
console.log(movie); // movie 로그 출력
Copy link

Choose a reason for hiding this comment

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

console.log는 삭제해주시는 게 좋을 것 같아요!

paya17

This comment was marked as duplicate.

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