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주차] SNIFF 미션 제출합니다. #12

Open
wants to merge 67 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
0488330
init: 프로젝트 세팅
oooppq Nov 6, 2023
c54f496
feat: netflix landing 구현
oooppq Nov 6, 2023
2c21a77
Merge pull request #1 from oooppq/feature/landing
oooppq Nov 6, 2023
0dee550
feat: navbar 컴포넌트 생성
oooppq Nov 6, 2023
f96a004
feat: landing 애니메이션 종료시 browse 페이지로 이동
oooppq Nov 6, 2023
6605b41
feat: srg 설정
oooppq Nov 6, 2023
8b78fc6
style: nav bar 스타일 적용
oooppq Nov 6, 2023
9917fac
feat: navbar 기능 구현
oooppq Nov 6, 2023
c5e74da
refactor: navbar 렌더링 방식 변경
oooppq Nov 6, 2023
48b009b
Merge pull request #2 from oooppq/feature/nav
oooppq Nov 6, 2023
86ca97a
chore: navbar 라우팅 수정 및 디렉토리 변경
oooppq Nov 8, 2023
a39fb88
feat: home navbar 컴포넌트 구성
oooppq Nov 8, 2023
5a008dd
style home navbar style 적용 완료
oooppq Nov 8, 2023
f72f0ea
chore: navbar(공통, 홈) sementic tag로 변경
oooppq Nov 8, 2023
0893eae
feat: content slider 컴포넌트 구성
oooppq Nov 8, 2023
2b5dee2
refactor: content의 container tag 변경
oooppq Nov 8, 2023
b84ffc7
style: content slider 스타일 적용
oooppq Nov 8, 2023
dd7a7d1
style: content slider 스크롤바 제거
oooppq Nov 8, 2023
a097775
feat: content slider 마우스로 drag 구현
oooppq Nov 8, 2023
96eb778
style: browse 페이지 크기 변경
oooppq Nov 8, 2023
7ec9cfc
style: slider 넘기기 버튼 추가
oooppq Nov 8, 2023
f0310d0
refactor: content slider 마우스로 drag 제거 및 이동 버튼 추가
oooppq Nov 8, 2023
42ba27e
chore: 코드 및 주석 정리
oooppq Nov 8, 2023
b1ef104
Merge pull request #3 from oooppq/feature/home/slider
oooppq Nov 8, 2023
35c6f4b
feat: home top 컴포넌트 구성
oooppq Nov 8, 2023
4b06445
style: home top style 적용
oooppq Nov 8, 2023
bb36436
feat: home top 기능 구현
oooppq Nov 8, 2023
b8d5fef
Merge pull request #4 from oooppq/feature/home/top
oooppq Nov 8, 2023
b90debb
feat : first api done
flowerseok Nov 8, 2023
734f547
feat : add api
flowerseok Nov 8, 2023
70d476a
feat: api 연동, preview 옵션설정
flowerseok Nov 9, 2023
7e1a32e
chore: global css bottom padding
flowerseok Nov 9, 2023
f8120d5
chore: css 수정
flowerseok Nov 9, 2023
962c69b
chore: 첫 화면 수정
flowerseok Nov 9, 2023
c2fdba9
chore: upload
flowerseok Nov 9, 2023
1570094
chore: 불필요 함수 삭제, defaultData수정
flowerseok Nov 9, 2023
8beee67
Merge pull request #5 from flowerseok/feat/Content
oooppq Nov 9, 2023
d983810
style: searchbar 디자인 적용 완료
oooppq Nov 14, 2023
10ddda9
style: search list의 header 디자인 적용
oooppq Nov 14, 2023
fd29aea
style: search list의 element 디자인 적용 완료
oooppq Nov 14, 2023
326b44f
feat: keyword search 기능 구현
oooppq Nov 14, 2023
9ac9473
feat: search 초기 데이터 설정
oooppq Nov 14, 2023
bac6d9b
style: 사소한 디자인 디테일 적용
oooppq Nov 14, 2023
577cb13
feat: query 초기화 버튼 기능 구현
oooppq Nov 14, 2023
0d6f94a
feat: 검색 결과 무한스크롤 구현 완료
oooppq Nov 14, 2023
aa77cf2
feat: 검색결과 memoization
oooppq Nov 14, 2023
5da8e26
feat: 검색결과 skeleton Element 구현
oooppq Nov 14, 2023
f20f9d0
style: no poster image의 스타일 변경
oooppq Nov 14, 2023
d178f61
Merge pull request #6 from oooppq/feature/search
oooppq Nov 14, 2023
3d01443
feat: detailpage api 연동, 초기구성완료
flowerseok Nov 15, 2023
6b7a21d
feature : click시 detailpage 경로수정
flowerseok Nov 15, 2023
65c282b
style : poster size, font size 수정
flowerseok Nov 15, 2023
3587f8e
style : overview가 하단 Navbar에 가리는거 수정
flowerseok Nov 16, 2023
7d2c543
Merge pull request #7 from flowerseok/feature/datail
oooppq Nov 16, 2023
3d9855d
style: 디테일 페이지 영화 설명 padding 추가
oooppq Nov 16, 2023
b958cfe
feat: 홈 슬라이더 element memoization
oooppq Nov 16, 2023
9a75b75
feat: 디테일 페이지 포스터 없을 때 default 이미지 추가
oooppq Nov 16, 2023
46ef60b
Merge pull request #8 from oooppq/feature/chore
oooppq Nov 16, 2023
132c601
chore: detailTop 컴포넌트의 사용되지 않는 prop 제거
oooppq Nov 16, 2023
9cd6134
refactor: 영화 정보 type에 overview 추가
oooppq Nov 16, 2023
186191b
refactor: 디테일 페이지 불필요한 라우팅 경로 삭제 및 기타 타입지정
oooppq Nov 16, 2023
2eedd96
Merge pull request #9 from oooppq/feature/chore
oooppq Nov 16, 2023
51e9c71
chore: 검색결과에도 detail 페이지 디렉토리 변화 적용
oooppq Nov 16, 2023
b1d0eb5
chore: 검색창에 공백 입력시 default 결과가 display되도록 변경
oooppq Nov 16, 2023
78aac31
Merge pull request #10 from oooppq/feature/chore
oooppq Nov 16, 2023
79767dd
hotfix: 홈화면 슬라이더 memoization 추가
oooppq Nov 17, 2023
2fab28a
hotfix: image optimization 설정 off
oooppq Nov 19, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.local
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
NEXT_PUBLIC_API_KEY="e76f188b77121ac1189879f8d38c1314"
6 changes: 6 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"extends": ["next/core-web-vitals", "prettier"],
"parserOptions": {
"project": "./tsconfig.json"
}
}
7 changes: 7 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
## PR 요약

> summary

## 변경된 점

> changes
30 changes: 30 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: git push into another repo to deploy to vercel

on:
push:
branches: [master]

jobs:
build:
runs-on: ubuntu-latest
container: pandoc/latex
steps:
- uses: actions/checkout@v2
- name: Install mustache (to update the date)
run: apk add ruby && gem install mustache
- name: creates output
run: sh ./build.sh
- name: Pushes to another repository
id: push_directory
uses: cpina/github-action-push-to-another-repository@master
env:
API_TOKEN_GITHUB: ${{ secrets.DAEGYUN_GITHUB_SECRET }}
with:
source-directory: 'output'
destination-github-username: oooppq
destination-repository-name: next-netflix-18th
user-email: ${{ secrets.DAEGYUN_GITHUB_EMAIL }}
commit-message: ${{ github.event.commits[0].message }}
target-branch: master
- name: Test get variable exported by push-to-another-repository
run: echo $DESTINATION_CLONED_DIRECTORY
36 changes: 36 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js
.yarn/install-state.gz

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# # local env files
# .env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
8 changes: 8 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"singleQuote": true,
"useTabs": false,
"trailingComma": "all",
"semi": true,
"printWidth": 80,
"tabWidth": 2
}
65 changes: 30 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,50 +1,45 @@
# 5주차 미션: Next-Netflix
## 패키지 매니저

## 서론
> yarn

안녕하세요, 프론트 운영진 **노수진**입니다 😸
### 이유

이번주부터는 새 프로젝트인 **Netflix 클론코딩**을 진행합니다. 이번 미션은 Next.js를 사용해 보며 SSR을 학습하고 Figma로 주어지는 디자인을 활용해 스타일링 하는 방법을 이해하는 것을 목표로 합니다.
- 딱히 없음. yarn berry나 pnpm 등의 신상 패키지 매니저를 쓰면서까지 빌드 시간을 단축시킬 프로젝트가 아님.
- npm에 비해 cli가 깔끔하고, 안내 log가 친절함.

또한 이번주부터는 프론트 페어와 함께하는 과제인 만큼 각 팀별로 미리 호흡을 맞춰 보는 좋은 기회가 될 것 같습니다. 모두 화이팅입니다🔥
### 설치

## 미션
- node 설치(아마 되어있을 듯)
- npm -g install yarn

### 미션 목표
### 기본 동작

- Next.js 사용법을 공부해봅니다.
- Figma로 주어지는 디자인으로 스타일링 하는 방식에 익숙해집니다.
- Git을 이용한 협업 방식에 익숙해집니다.
- yarn add( = npm install ~ )
- yarn create( = npx ~ )
- 프로젝트 cli(yarn dev, build, start, lint 등, = npm run ~ )

### 기한
## 프로젝트 시작

- 2023년 11월 10일 (기한 엄수)
- 이 repo를 자신의 repo에 fork
- git clone https://github.com/[your_id]/next-netflix-18th.git
- 프로젝트 디렉토리에서 yarn install

### 필수 요건
## branch 전략

- [결과화면](https://next-netflix-17th-sepia.vercel.app/)의 랜딩 페이지와 메인 페이지를 구현합니다.
- [Figma](https://www.figma.com/file/UqdXDovIczt1Gl0IjknHQf/Netflix?node-id=0%3A1)의 디자인을 그대로 구현합니다.
- Open api를 사용해서 데이터 패칭을 진행합니다. (ex. [themoviedb API](https://developers.themoviedb.org/3/getting-started/introduction))
- `yarn`, `yarn berry`, `npm`, `pnpm`등 패키지 매니저를 직접 선택해 Next.js를 세팅해 봅니다.
- 기능을 구현하기 전 team repo에서 최신 버전의 master 상태를 pull한 후 개발 진행
- 큼지막한 기능 별로 feature/기능이름 과 같은 형태로 branch 생성 후 코드 작성
- 작성이 완료되면 바로 merge 하는게 아니라 pr 생성(new pull request 버튼 누르면 자동으로 pr template이 적용되어 있음)
- 상대방이 approve 하면 merge 하는 것을 원칙으로 하나 서로 얘기해보고 괜찮다 싶으면 스스로 master에 merge(무튼 merge 하기 전에 상대방에게 확인받기는 해야 함)

### 선택 사항
## 배포

- SSR(Server Side Rendering)을 적용해서 구현합니다.
- 웹 폰트를 사용합니다.
- 반응형을 고려합니다.
- 팀 repo 그대로 vercel에 배포하려면 요금을 지불해야 함
- 따라서, 팀 repo를 오대균 github에 fork 하여, 오대균 repo에서 배포 함
- 수동으로 배포하면 번거로우니 다음과 같은 flow로 배포되도록 설정함
> 1. team repo master branch에 push 발생
> 2. 오대균 repo의 master branch에 변경사항 자동으로 적용
> 3. vercel이 이를 인식하고 자동으로 배포 반영
Comment on lines +36 to +41
Copy link

Choose a reason for hiding this comment

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

저희는 vercel 을 사용한적이 없어 아직 팀 레포 그대로 배포하도 공짜로 사용 가능하여 그냥 했는데, github action 을 이용하여 이를 해결하신점 매우 멋지네요!!!^^


## **Key Question**
## 궁금한 점이 있다면

- Server Side Rendering과 Client Side Rendering의 차이
- SEO란
- 전반적인 협업 과정

## 링크 및 참고자료

- [랜딩페이지 영상](https://lottiefiles.com/kr/)
- [Next.js Docs](https://beta.nextjs.org/docs)
- [Next.js 13에서 변한 것들](https://velog.io/@hang_kem_0531/Next.js-13%EC%9D%B4-%EB%82%98%EC%99%80%EB%B2%84%EB%A0%B8%EB%8B%A4)
- [Next.js 14에서 변한 것들](https://velog.io/@lee_1124/Next.js-14-%EC%97%85%EB%8D%B0%EC%9D%B4%ED%8A%B8)
- [Git 협업 가이드](https://velog.io/@jinuku/Git-%ED%98%91%EC%97%85-%EA%B0%80%EC%9D%B4%EB%93%9C)
- [디자이너와 개발자가 협업하기 위한 피그마 기본 기능](https://chingguhl.tistory.com/entry/%EA%B0%9C%EB%B0%9C%EC%9E%90%EA%B0%80-%EA%BC%AD-%EC%95%8C%EC%95%84%EC%95%BC-%ED%95%A0-%ED%94%BC%EA%B7%B8%EB%A7%88-10%EA%B0%80%EC%A7%80-%EA%B8%B0%EB%8A%A5-%EB%94%94%EC%9E%90%EC%9D%B4%EB%84%88%EC%99%80-%EA%B0%9C%EB%B0%9C%EC%9E%90%EA%B0%80-%ED%98%91%EC%97%85%ED%95%98%EA%B8%B0-%EC%9C%84%ED%95%9C-%ED%94%BC%EA%B7%B8%EB%A7%88-%EA%B8%B0%EB%B3%B8-%EA%B8%B0%EB%8A%A5)
- [React에서 무한 스크롤 구현하기](https://tech.kakaoenterprise.com/149)
- 아무 때나 말하세요
51 changes: 51 additions & 0 deletions app/browse/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React from 'react';
import ContentsSlider from '@/components/browse/ContentsSlider';
import HomeNavBar from '@/components/browse/HomeNavBar';
import HomeTop from '@/components/browse/HomeTop';
import { TContent } from '@/types';
import { getMovies } from '@/utils/Api';

interface BrowseProps {
searchParams: { [key: string]: string | undefined };
Copy link
Member

Choose a reason for hiding this comment

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

저는 useSearchParams를 사용했는데 직접 구현하신 거 좋은 것 같습니다

}

const Browse = async ({ searchParams }: BrowseProps) => {
const Top = await getMovies('top_rated');
const Popular = await getMovies('popular');
const Upcoming = await getMovies('upcoming');
const Nowplaying = await getMovies('now_playing');

const defaultData = {
rank: 1,
category: 'Top Rate',
posterPath: Top[0].poster_path,
};

return (
<div className="bg-black w-full min-h-full pb-12 relative">
<HomeNavBar />
<HomeTop
posterPath={searchParams.posterPath || defaultData.posterPath}
rank={
searchParams.rank
? Number(searchParams.rank)
: searchParams.posterPath
? null
: defaultData.rank
}
category={searchParams.category || defaultData.category}
/>
<ContentsSlider
title="Preview"
isRanking={false}
isPreview={true}
contents={Nowplaying}
/>
<ContentsSlider title="Nigeria Today" isRanking={true} contents={Top} />
<ContentsSlider title="Popular" isRanking={false} contents={Popular} />
<ContentsSlider title="Upcoming" isRanking={false} contents={Upcoming} />
Comment on lines +38 to +46
Copy link

Choose a reason for hiding this comment

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

정보를 리스트 선언 후 map 함수로 렌더링 한다면 가독성과 추후 슬라이더 추가시에도 편리할 것 같다는 개인적인 의견 드립니다 ㅎㅎ

Suggested change
<ContentsSlider
title="Preview"
isRanking={false}
isPreview={true}
contents={Nowplaying}
/>
<ContentsSlider title="Nigeria Today" isRanking={true} contents={Top} />
<ContentsSlider title="Popular" isRanking={false} contents={Popular} />
<ContentsSlider title="Upcoming" isRanking={false} contents={Upcoming} />
const sliderData=[
{
title: "Preview",
movieData: await getMovies('now_playing'),
isRanking: false,
isPreview:true
},
{
title: "Nigeria Today",
movieData: await getMovies('top_rated'),
isRanking: true,
isPreview:false
},
{
title: "Popular",
movieData: await getMovies('popular'),
isRanking: false,
isPreview:false
},
{
title: "Upcoming",
movieData: await getMovies('upcoming'),
isRanking: false,
isPreview:false
}
]
....
{sliderData.map((data,index)=>(
<ContentsSlider
key={data.title}
title={data.title}
isRanking={data.isRanking}
isPreview={data.isPreview}
contents={data.movieData}
/>
))}

Copy link
Member

Choose a reason for hiding this comment

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

저도 배워갑니다~!

</div>
);
};

export default Browse;
Binary file added app/favicon.ico
Binary file not shown.
17 changes: 17 additions & 0 deletions app/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
@import url('https://fonts.cdnfonts.com/css/sf-pro-display');
@tailwind base;
@tailwind components;
@tailwind utilities;

html {
width: 100%;
height: 100%;
}

body {
font-family: 'SF Pro Display', sans-serif;
background-color: black;
width: 100%;
height: 100%;
}

25 changes: 25 additions & 0 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import type { Metadata } from 'next';
import './globals.css';
import NavBar from '@/components/common/NavBar';

export const metadata: Metadata = {
title: 'sniff-netflix',
description: 'netflix clone project',
viewport:
'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0',
};

export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
{children}
<NavBar />
</body>
</html>
);
}
21 changes: 21 additions & 0 deletions app/movies/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from 'react';
import DetailTop from '@/components/detail/DetailTop';
import DetailOverview from '@/components/detail/DetailOverview';
import { getMovieDetails } from '@/utils/Api';
import { TContent } from '@/types';

interface DetailPageProps {
params: { id: string };
}
const Page = async ({ params }: DetailPageProps) => {
const movie: TContent = await getMovieDetails(params.id);

return (
<div className="min-h-screen bg-black">
<DetailTop posterPath={movie.poster_path} />
<DetailOverview title={movie.title} overview={movie.overview} />
</div>
);
};

export default Page;
15 changes: 15 additions & 0 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import dynamic from 'next/dynamic';

const page = () => {
const Logo = dynamic(() => import('@/components/LandingLogo'), {
Copy link
Member

Choose a reason for hiding this comment

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

저도 다음에는 dynamic을 이용해서 구현해봐야겠어요~!

ssr: false,
});

return (
<div className="w-full h-full bg-black flex align-middle">
<Logo />
</div>
);
};

export default page;
85 changes: 85 additions & 0 deletions app/search/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/* eslint-disable react-hooks/exhaustive-deps */
Copy link

Choose a reason for hiding this comment

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

이 페이지는 최상단에 use client 를 선언하셨는데 시간이 없어 리팩토링을 하지 못한것인지 특별한 이유가 있는지 개인적으로 궁금하네요 ㅎㅎ

Copy link
Author

Choose a reason for hiding this comment

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

페이지 내에서 리엑트 훅을 사용하려면 csr로 페이지를 구성해야 하는 것 같드라구요!

'use client';

import SearchBar from '@/components/search/SearchBar';
import SearchResultList from '@/components/search/SearchResultList';
import { useDebounce } from '@/hooks/useDebounce';
import { TContent } from '@/types';
import { getMovies, getSearchedMovies } from '@/utils/Api';
import { useEffect, useState } from 'react';
import { useInView } from 'react-intersection-observer';

const SearchPage = () => {
const [movies, setMovies] = useState<TContent[]>([]);
const [keyword, setKeyword] = useState<string>('');
const [init, setInit] = useState<boolean>(true);
const [ref, inview] = useInView();
const [pageNum, setPageNum] = useState<number>(1);
const [totalPageNum, setTotalPageNum] = useState<number>(1);

useEffect(() => {
if (!keyword) {
(async () => {
// next의 fetch는 같은 요청에 대해 caching을 진행하므로,
// 첫 요청 이후에는 caching된 데이터를 가져올 것(?)
const defaultMovies = await getMovies('popular');
setMovies(defaultMovies);
setPageNum(1);
setTotalPageNum(1);
setInit(false);
})();
}
}, [keyword]);

Choose a reason for hiding this comment

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

서치 페이지에서 검색 전 popular 데이터 불러올 때 몇개의 데이터에 문제가 있는 것 같아요..!
스크린샷 2023-11-19 오후 4 14 57

Copy link
Author

Choose a reason for hiding this comment

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

지금 보니까 vercel 뭐 가격 정책때문에 이미지 요청이 막히는 것 같네요ㅋㅋㅋ.. 뭐 무슨 limit이 있다고 했는데 오늘 딱 그 limit에 도달했나봐요 함 해결해볼게요ㅜㅜ

Copy link
Author

Choose a reason for hiding this comment

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

next 이미지 optimization 설정을 꺼주니까 해결되었네요!


useEffect(() => {
if (pageNum > 1) {
(async () => {
const data = await getSearchedMovies(keyword, pageNum);
setMovies([...movies, ...data.results]);
})();
}
}, [pageNum]);

useEffect(() => {
if (inview && pageNum < totalPageNum) {
setPageNum(pageNum + 1);
}
}, [inview]);
Comment on lines +19 to +47
Copy link

Choose a reason for hiding this comment

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

필요한 부분을 세부 클라이언트 컴포넌트에 선언한다면 최상단에 'use client'를 없앨수도 있겠네요 ㅎㅎ 저희도 시간 때문에 서치페이지 'use client'로 선언해버렸는데 이제 리팩토링 해봐야됩니다 ㅋㅋㅋㅋㅋㅋ

Copy link
Author

Choose a reason for hiding this comment

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

약간 귀찮아서 걍 페이지 자체를 csr로 구성했는데 ssr로 구성하고 내부에 csr 컴포넌트를 넣는 것이 성능적으로 뛰어나다면 앞으로 그렇게 해봐야겠네요ㅎㅎ


const handleOnChangeQuery = async (
e: React.ChangeEvent<HTMLInputElement>,
) => {
const query = e.target.value.trim();
if (query) {
const data = await getSearchedMovies(query);
setMovies(data.results);
setPageNum(data.page);
setTotalPageNum(data.total_pages);
}
setKeyword(query);
if (!query) setInit(true);
};
Comment on lines +49 to +61

Choose a reason for hiding this comment

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

handleChangeQuery를 통해 검색어 변화가 있을때 이렇게 처리를 할수도 있겠네요..! 저희는 불러온 리스트에서 필터링을 했었는데, 이런 방법도 있군요!


return (
<div>
<SearchBar
keyword={keyword}
setKeyword={setKeyword}
setInit={setInit}
handleOnChangeQuery={useDebounce(handleOnChangeQuery, 500)}
/>
Comment on lines +68 to +70
Copy link

Choose a reason for hiding this comment

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

debounce 를 통해 과도한 데이터 fetching 방지하신 디테일 좋네요 ㅎㅎ

<h2 className="text-white text-[27px] ml-2.5 mt-5 mb-4 font-bold">
{keyword.length === 0 ? 'Polular' : 'Top Searches'}
</h2>
{movies.length || init ? (
<SearchResultList movies={movies} />
) : (
<div className="text-white text-center mt-20 px-3 break-words">{`There are no movies that matched "${keyword}".
`}</div>
)}
<div className="" ref={ref}></div>
</div>
);
};

export default SearchPage;
Loading