사실 이 부분은 내 아이디어 (?) 로 가장 하고 싶었던 부분이라 좀 재밌게 코드를 작성해보고
그만큼 시행착오도 좀 겪었던 부분이다.
완성본을 gif파일로 올리려고 했는데 안나온다.. ^^
그냥 깃허브 배포 주소 로 확인해보길 바란다 후후
S-FLEX
뜯어본다면,

Genre에 마우스를 올리면, 이렇게 Movie, Tv를 선택할 수 있는 DropDownMenu가 나타나고, 선택하면 위에는 Movie이 Genre가,

위에는 Tv Show의 Genre가 이렇게 데이터를 불러오게 된다.
이제 여기서 원하는 Genre를 선택하면!

선택한 Genre에 해당하는 작품을 보여주게 된다!
이제 코드를 살펴보러 가보자!
export function getGenreMovie(): Promise<IGetGenreItem> {
return fetch(
`${BASE_PATH}/genre/movie/list?api_key=${API_KEY}&language=ko-KR`
).then((response) => response.json());
}
export function getMoviesByGenre(genreId: number): Promise<IGetMovieByGenre> {
return fetch(
`${BASE_PATH}/discover/movie?api_key=${API_KEY}&with_genres=${genreId}&language=ko-KR`
).then((response) => response.json());
}
export function getGenreTv(): Promise<IGetGenreItem> {
return fetch(
`${BASE_PATH}/genre/tv/list?api_key=${API_KEY}&language=ko-KR`
).then((response) => response.json());
}
export function getTvByGenre(genreId: number): Promise<IGetTvByGenre> {
return fetch(
`${BASE_PATH}/discover/tv?api_key=${API_KEY}&with_genres=${genreId}&language=ko-KR`
).then((response) => response.json());
}
api는 Genre에 대한 Api를 받아오고 그 Genre에 해당하는 영화를 가져오는 Api를 Movie, Tv를 각각 가져왔다.
(movie와 tv의 코드 구조는 거의 똑같기 때문에 Movie만 살펴보겠다)
const Genre = () => {
const [selectGenreId, setSelectGenreId] = useState<number | null>(null);
const [selectedGenre, setSelectedGenre] = useState<string | null>(null);
const [selectedMovieId, setSelectedMovieId] = useState<number | null>(null);
const { data: genreData, isLoading: genresLoading } = useQuery<IGetGenreItem>(
'genre',
getGenreMovie
);
const { data: moviesData, isLoading: moviesLoading } =
useQuery<IGetMovieByGenre>(['moviesByGenre', selectGenreId], () =>
getMoviesByGenre(selectGenreId!)
);
const handleGenreSelection = (genreId: number, genreName: string) => {
setSelectGenreId(genreId);
setSelectedGenre(genreName);
};
const handleMovieClick = (movieId: number) => {
setSelectedMovieId(movieId);
};
return (
<Container>
{genresLoading ? (
<Loader>Loading...</Loader>
) : (
<GenreContainer>
<GenreTitle>어떤 세계에 몰입하고 싶으세요?</GenreTitle>
<GenreList>
{genreData?.genres.map((genre) => (
<GenreButton
key={genre.id}
onClick={() => handleGenreSelection(genre.id, genre.name)}
>
#{genre.name}
</GenreButton>
))}
</GenreList>
</GenreContainer>
)}
{selectGenreId ? (
<SliderGenre
onMovieClick={handleMovieClick}
genre={selectedGenre || ''}
movies={moviesData?.results || []}
/>
) : null}
</Container>
);
};
export default Genre;
genreDate를 하나씩 쫙 뿌려준 뒤, 그 genre 중 선택한 genre의 id와 name을 handleGenreSelection 함수를 통해서
setSelectGenreId(genreId);
setSelectedGenre(genreName);
를 각각 넘겨준 뒤,
selectGenreId가 있다면?
선택한 Genre에 대한 작품을 보여주는 <SliderGenre/> 에 정보들을 넘겨준다.
(여기서 SliderGenre와 GenreBigMovie에 관한 부분은 이전 Home, Tv Show와 거의 동일하기 때문에 설명은 생략하겠다)
DropdownMenu는 <Header/> 부분에서 먼저 살펴보아야 한다
<Header/>
const [dropdownVisible, setDropdownVisible] = useState(false);
const handleMouseEnter = () => setDropdownVisible(true);
const handleMouseLeave = () => setDropdownVisible(false);
...
<Item
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
Genre
{genreMovieMatch || genreTvShowMatch ? (
<Circle layoutId="circle" />
) : null}
<DropdownMenu
isVisible={dropdownVisible}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
/>
</Item>
마우스가 올라갔을 때, setDropdownVisible의 상태를 true,
마우스가 내려갔을 때, setDropdownVisible의 상태를 false를 설정해서
DropdownMenu가 나타나고 사라지는 상태를 isVisible 속성으로 <DropdownMenu/>d 에게 넘겨주었다
const dropdownVariants = {
hidden: {
opacity: 0,
y: -20,
},
visible: {
opacity: 1,
y: 0,
transition: {
duration: 0.3,
},
},
};
const DropdownMenu = ({
isVisible,
onMouseEnter,
onMouseLeave,
}: IDropdownProps) => {
return (
<AnimatePresence>
{isVisible && (
<DropdownContainer
initial="hidden"
animate="visible"
exit="hidden"
variants={dropdownVariants}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
>
<DropdownItem to="/genre/movies">Movie</DropdownItem>
<DropdownItem to="/genre/tv">TV</DropdownItem>
</DropdownContainer>
)}
</AnimatePresence>
);
};
export default DropdownMenu;
Header에서 받은 isVisible, onMouseEnter, onMouseLeave 속성을 이용해
animation 속성을 지정하고,
dropdownVariant를 간단하게 살펴보자면, initial="hidden", animate="visible"로 지정해 주었는데,
원래 상태 (initial)일 때에는 opacity : 0으로 보이지 않게 되고,
animate 즉 마우스를 올렸을 때, y : -20이 0으로 오면서 오른쪽으로 이동하는 것처럼 보이며, opacity : 1로 화면에 보이게 된다.
이후 Movie를 눌렀을 때, /genre/movies로 이동,
Tv를 눌렀을 때, /genre/tv 이동하게 코드를 작성해 두었다.