React JS 마스터클래스(NOMFLIX CLONE) - Movie Modal

짜스의 하루 ·2024년 7월 8일

Movie Modal

넷플릭스에서는 슬라이더에 있는 영화를 클릭하면 우리는 그 해당 영화의 modal을 볼 수 있다

해당 영화를 클릭하게 되면 --> 해당 영화의 아이디를 받아와 --> 링크를 통해서 영화의 정보 (뭐 예를 들면 예고편 , 평점 , 줄거리 등등)을 볼 수 있는 모달창이 뜨게 된다

즉, / 메인 페이지였던 링크가 해당 영화를 클릭하면서 /movies/movieId로 이동 후, 해당 영화의 모달창을 띄우게 된다는 것이다.

여기서 useMatch(), useNavigate()를 사용할 수 있다.

먼저, <Box/> (슬라이더에 해당하는 영화) 가 열리는지 확인하기 위해 --> 클릭했을 때, 해당 영화의 movidId를 --> useNavigate()에 넘겨주어서 /movies/movieId 이동하도록 해야 한다.

 const navigate = useNavigate();
 
 const onBoxClicked = (movieId: number) => {
    navigate(`/movies/${movieId}`);
  };

const navigate = useNavigate() : useNavigate 훅을 호출하여 navigate 함수로 할당 --> 이 함수는 프로그램적으로 페이지를 이동할 때 사용한다.

onBoxClicked : onBoxClicked라는 이름의 함수를 정의한다. 이 함수는 매개변수로 movieId를 받는다.
이후 navigate 함수를 사용하여, movieId를 포함한 URL로 이동하게 된다.

자, 이제 <Box/> 컴포넌트를 눌렀을 때, 해당 영화의 Id를 받아오는 것까지 끝냈다.
이제 Box 컴포넌트를 눌렀을 때 --> 모달창이 나올 수 있도록 간단하게 만들어보자!

const bigMovieMatch = useMatch('/movies/:movieId');

.
.
.

<AnimatePresence>
              {bigMovieMatch ? (
                <motion.div
                  style={{
                    position: 'absolute',
                    width: '40vw',
                    height: '80vh',
                    backgroundColor: 'red',
                    top: 20,
                    left: 0,
                    right: 0,
                    margin: '0 auto',
                  }}
                />
              ) : null}
            </AnimatePresence>

const bigMovieMatch = useMatch('/movies/:movieId') :
useMatch는 react-router-dom에서 제공하는 훅으로, 현재 URL이 주어진 패턴 ('/movies/:movieId')과 일치하는지 확인한다.

'/movies/:movieId' 경로 패턴은 /movies/5253535 와 같은 경로와 일치하며, :movieId 는 URL에서 변수로 간주된다.

경로가 일치할 경우 bigMovieMatch는 경로와 관련된 매칭 객체를 반환하며, 일치하지 않으면 null을 반환하게 된다.

bigMovieMatch ? ( 통해서 조건부 렌더링을 통해 bigMovieMatch가 true일 때만 <motion.div>를 렌더링하게 된다.

그런데, 여기서 <Box/> 컴포넌트를 눌렀을 때 --> 이 해당 모달이 뜨는 건데, 하나처럼 같이 동작하면 좋을 것 같다 --> layoutId를 주면 된다

framer-motion에서 layoutId를 사용하면 두 컴포넌트가 같은 애니메이션 트랜지션을 공유할 수 있다.
이를 통해 <Box/>를 클릭했을 때 해당 영화의 정보가 팝업(모달)으로 부드럽게 전환되는 애니메이션 효과를 쉽게 구현할 수 있다.

이때, layoutId는 고유한 값을 주어야 하는데, 각각의 movieId를 주면 해결된다


짜잔!

요런식으로 모달창이 등장하게 된다
쿠쿠


모달창이 등장했을 때, 모달창 밖으로 어두운 배경을 주기 위해서 <Overlay/> 컴포넌트를 추가해 주었다.

const Overlay = styled(motion.div)`
  position: fixed;
  top: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  opacity: 0;
`;

또한, <Overlay/> 컴포넌트를 클릭했을 때,
다시 / 로 돌아갈 수 있도록 클릭 이벤트도 추가해 주었다.

 const onOverlayClicked = () => {
    navigate('/');
  };

그럼 이제 모달창이 등장하고, 밖에 아무곳을 눌러도, 다시 메인 화면으로 이동하는 것을 확인할 수 있다!


useScroll

위의 사진을 보면 모달창의 문제점을 하나 찾을 수 있다.
모달창의 위치가 top : 50으로 고정되어 있어서 스크롤을 무수히 내려도 top : 50에 고정되어 있다는 점이다.

그럼 내가 스크롤한 것에 맞춰서 모달창이 띄워졌으면 좋겠는데 ..? --> useScroll()를 사용해서 현재 내가 스크롤한 y의 값을 가져오면 된다.

const { scrollY } = useScroll();
로 scrollY의 값을 가져온 뒤,

top 속성의 값으로 scrollY를 넣어주면 된다.
그럼 스크롤된 화면에 맞춰서 화면 가장 상단에 나타나는데, 여백을 주기 위해
scrollY의 값을 get()함수로 직접 가져온 뒤 + 100을 더해주었다.

그럼 이렇게 스크롤을 내려도, 스크롤 내린 화면에 맞춰 + 100한 위치에 모달창이 등장하는 것을 확인할 수 있다!

이제 모달창에 다양한 정보들을 뿌려주자

간단하게 해당 이미지, 제목, 줄거리 정도만 화면에 뿌려줄 예정이다.
그럼 어떻게 해야할까 ?

--> 먼저, 클릭한 영화의 movieId가 data에 있는 Id와 같은지 비교하고,맞다면 화면에 뿌려주도록 하면 될 것이다!

const clickedMovie =
    bigMovieMatch?.params.movieId &&
    data?.results.find(
      (movie) => movie.id + '' === bigMovieMatch.params.movieId
    );

const bigMovieMatch = useMatch('/movies/:movieId') bigMovieMatch에파라미터로 받아온 movieId가 있다면, data.result에서 찾아낸다!
무엇을 ? movie.id === bigMovieMatch.params.movieId 같은지를

그리고 clickedMovie가 true일때 ? --> clickedMovie에서 backdrop_path, title, overview를 불러온다!

업로드중..
이렇게 이미지, 제목, 줄거리를 불러온 것을 확인할 수 있다.

profile
2024. 01. 02 ~ 백앤드 공부 시작, 2024. 04.01 ~ 프론트 공부 시작

0개의 댓글