↓↓↓↓이 프로젝트의 전체 코드는 GitHub에서 확인하실 수 있습니다.↓↓↓↓
https://github.com/GangHyun95/youtube
GitHub - GangHyun95/youtube: with typescript
with typescript. Contribute to GangHyun95/youtube development by creating an account on GitHub.
github.com
프로젝트에서 VideoDetail 페이지로 이동할 때 useNavigate를 통해 데이터를 전달하는 방식을 사용했었는데요.
VideoCard와 RelatedVideoList에서 사용하는 데이터의 출처가 다르다 보니 문제가 발생했습니다.
이번 포스팅에서는 이 문제를 해결하는 과정과 VideoCard에 마우스를 올렸을 때 해당 비디오ID의 iframe을 생성하여 미리보기 영상이 재생되는 것처럼 보이도록 구현한 방법을 다루겠습니다.
VideoDetail 페이지 문제의 원인
1. VideoCard
- YouTube의 video 엔드포인트를 사용해 데이터를 요청하고, 이때 statistics 정보를 포함했습니다. 또한, 요청한 데이터에 채널 정보를 추가하여 반환했습니다.
2. RelatedVideoList
- YouTube의 playlists 엔드포인트를 사용했는데, 이 엔드포인트에서는 statistics 정보나 채널 정보가 포함되지 않았습니다.
이 차이로 인해 VideoDetail 페이지에서 필요한 데이터가 없어서 오류가 발생했습니다.
해결 과정
처음에는 useNavigate로 데이터를 전달하지 않고, VideoDetail 페이지가 마운트될 때마다 useQuery로 무조건 데이터를 요청하는 방식으로 수정하려고 했습니다.
그러다가 React Query의 enabled 속성을 알게 되었고 이걸 이용하면 특정 조건에서만 데이터를 요청할 수 있다는 걸 알았습니다.
그래서 useLocation을 통해 전달된 데이터가 없을 때만 useQuery가 활성화되도록 코드를 수정했습니다.
결과적으로 useNavigate로 전달된 데이터가 있으면 그걸 쓰고 없을 때만 API를 호출해서 비디오 데이터를 받아오게 처리할 수 있었습니다.
const { videoId } = useParams();
const location = useLocation();
const stateVideo = location.state?.video;
const { data: fetchedVideo, isLoading } = useQuery({
queryKey: ["video", videoId],
queryFn: () => YoutubeApi.getVideoById(videoId || ""),
staleTime: 60000,
gcTime: 1000 * 60 * 10,
refetchOnWindowFocus: false,
refetchOnMount: false,
refetchOnReconnect: false,
enabled: !stateVideo,
});
const video = stateVideo || fetchedVideo;
단일 비디오 ID로 데이터 요청 함수 추가
YouTube API에서 단일 비디오 ID로 비디오 데이터와 함께 채널 정보를 추가해서 반환하는 함수를 추가했습니다.
async getVideoById(videoId: string) {
const response = await this.httpClient.get("videos", {
params: {
part: "snippet,statistics",
id: videoId,
},
});
const channelId = response.data.items[0].snippet.channelId;
const channelResponse = await this.httpClient.get("channels", {
params: {
part: "snippet,contentDetails,statistics",
id: channelId,
},
});
return {
...response.data.items[0],
channelDetails: channelResponse.data.items[0],
};
}
VideoCard의 마우스 hover 미리보기 기능
VideoCard에 마우스를 올리면 해당 비디오ID의 iframe을 썸네일 위에 생성하고 재생시켜 마치 미리보기 영상이 재생되는 것처럼 구현하였습니다.
const [isHovered, setIsHovered] = useState(false);
const handleMouseEnter = () => {
setIsHovered(true);
};
const handleMouseLeave = () => {
setIsHovered(false);
};
return (
<li
className={cardClassName}
ref={ref}
onClick={() => navigate(`/videos/watch/${video.id}`, { state: { video } })}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
<section className={styles['img-container']}>
<img
className={styles.img}
src={thumbnails?.maxres?.url || (keyword ? thumbnails.high.url : thumbnails.medium.url)}
alt={title}
/>
{isHovered && (
<iframe
className={styles.video}
src={`https://www.youtube.com/embed/${video.id}?autoplay=1&mute=1&controls=0&playlist=${video.id}`}
frameBorder="0"
allow="autoplay; encrypted-media"
allowFullScreen
title={title}
></iframe>
)}
</section>
</li>
);
'React > Youtube' 카테고리의 다른 글
YouTube Data API를 이용한 Youtube Clone - 6 (0) | 2024.09.04 |
---|---|
YouTube Data API를 이용한 Youtube Clone - 5 (1) | 2024.09.02 |
YouTube Data API를 이용한 Youtube Clone - 4 (5) | 2024.09.01 |
YouTube Data API를 이용한 Youtube Clone - 3 (0) | 2024.08.29 |
YouTube Data API를 이용한 Youtube Clone - 2 (0) | 2024.08.28 |