프로젝트/영화 목록 (Netflix) 앱

영화목록 (Netflix) 앱 5 - 상세페이지 만들기

syleemomo 2021. 11. 24. 08:21
728x90

 

* 상세페이지 라우트 추가하기

import React from "react"
import ReactDOM from "react-dom"
import { BrowserRouter, Route, Routes } from "react-router-dom"
import { Register, Login, Home, Detail } from 'pages'

import './index.css'

const App = () => {
  return (
    <div>
      <Routes>
          <Route path='/' element={<Register/>}/>
          <Route path="/login" element={<Login/>}/>
          <Route path="/home" element={<Home/>}/>
          <Route path='/detail' element={<Detail/>}/>
      </Routes>
    </div>
  );
};
  
ReactDOM.render(<BrowserRouter>
                  <App />
                </BrowserRouter>, 
                document.getElementById("app"));

index.js 파일을 위와 같이 수정하자! 

import { Register, Login, Home, Detail } from 'pages'

Detail 페이지 컴포넌트를 임포트한다.

 <Route path='/detail' element={<Detail/>}/>

Detail 페이지에 대한 라우트를 추가한다. 

 

* 상세페이지 구현하기

export { default as Register } from './Register'
export { default as Login } from './Login'
export { default as Home } from './Home'
export { default as Detail } from './Detail'

pages > index.js 파일에 Detail 페이지 컴포넌트를 내보낸다. 

import React from 'react'
import { Movie } from 'components'
import { useLocation } from 'react-router-dom'

const Detail = () => {
    const location = useLocation()
    const { movie } = location.state
    return (
        <div>
            <Movie title={movie.title} 
                    genres={movie.genres} 
                    cover={movie.medium_cover_image} 
                    summary={movie.summary}
                    year={movie.year}>    
            </Movie>
            <p>{movie.summary}</p>
        </div>
    )
}
export default Detail

pages 폴더에 Detail.js 파일을 생성하고 위와 같이 작성하자!

import { Movie } from 'components'

상세페이지에서 사용자가 선택한 특정 영화에 대한 정보를 보여주기 위하여 Movie 컴포넌트를 임포트한다.

import { useLocation } from 'react-router-dom'

홈화면에서 Link 컴포넌트로부터 전달된 값을 조회하기 위하여 useLocation 함수를 임포트한다. 

const location = useLocation()
const { movie } = location.state

홈화면에서 Link 컴포넌트로부터 전달된 movie 데이터를 조회한다. useLocation 함수로부터 반환된 location 객체는 state 프로퍼티를 가지고 있다. 해당 프로퍼티에서 Link 컴포넌트로부터 전달된 값을 조회할 수 있다. 

<div>
    <Movie title={movie.title} 
            genres={movie.genres} 
            cover={movie.medium_cover_image} 
            summary={movie.summary}
            year={movie.year}>    
    </Movie>
    <p>{movie.summary}</p>
</div>

Movie 컴포넌트를 화면에 렌더링하고, 홈화면에서 전달된 movie 데이터로부터 영화 줄거리 요약 정보인 summary 데이터를 함께 렌더링한다. 

 

* 홈화면에서 특정 영화 클릭시 상세페이지로 영화 정보 넘겨주기

import React, { useState, useEffect } from 'react'
import { Link } from 'react-router-dom'

import { Movie, Loading, Input, Button } from 'components'
import './Home.css'

const Home = () => {
    const [loading, setLoading] = useState(true)
    const [movies, setMovies] = useState([])
    const [query, setQuery] = useState('')
    const [isSorted, setIsSorted] = useState(-1)
    

    useEffect( () => {
        fetch('https://yts.mx/api/v2/list_movies.json?limit=20')
        .then( res => res.json())
        .then( result => {
            const {data: {movies}} = result
            console.log(movies)
            setLoading(false)
            setMovies(movies)
        })
    }, [])

    const handleChange = (e) => {
        const { value } = e.target
        setQuery(value)
    }

    const sortByYear = (e) => {
        setIsSorted(isSorted * -1)
    }

    const homeUI = movies
                        .filter(movie => {
                            const title = movie.title.toLowerCase()
                            const genres = movie.genres.join(' ').toLowerCase()
                            const q = query.toLowerCase()
                        
                            return title.includes(q) || genres.includes(q)
                        })
                        .sort( (a, b) => {
                            return (b.year - a.year) * isSorted;
                        })
                        .map(movie =>
                            <Link key={movie.id}  
                                  to='/detail'
                                  state={{ movie }} 
                                  style={{ textDecoration: 'none', color: 'white'}}
                            >
                                
                                <Movie 
                                        title={movie.title} 
                                        genres={movie.genres} 
                                        cover={movie.medium_cover_image} 
                                        summary={movie.summary}
                                        year={movie.year}
                                       />
                            </Link> 
                                    )

    return (
        <>
            {loading? <Loading/>: <div className='Home-container'>
                                    <Input name='search' type='text' placeholder='Search movies ...' value={query} onChange={handleChange}/>
                                    <Button handleClick={sortByYear}>정렬</Button>
                                    <div className='Home-movies'>{homeUI}</div>
                                  </div>}
        </>
    )
}

export default Home

Home.js 파일을 위와 같이 수정하자!

import { Link } from 'react-router-dom'

사용자가 특정 영화를 클릭했을때 상세페이지로 이동하기 위하여 Link 컴포넌트를 임포트한다. 

<Link key={movie.id}  
      to='/detail'
      state={{ movie }} 
      style={{ textDecoration: 'none', color: 'white'}}
>

    <Movie 
            title={movie.title} 
            genres={movie.genres} 
            cover={movie.medium_cover_image} 
            summary={movie.summary}
            year={movie.year}
           />
</Link>

사용자가 특정 영화를 클릭했을때 상세페이지로 이동하기 위하여 Movie 컴포넌트를 Link 컴포넌트로 한번더 감싸준다. key 속성은 리스트의 최상단에 위치해야 하므로 Movie 컴포넌트에 있던 key 속성을 Link 컴포넌트로 이동한다. 

Link 컴포넌트의 to 속성에 '/detail' 로 설정했으므로 사용자가 특정영화를 클릭하면 /detail 경로로 이동하면서 Detail 페이지를 보여준다. state 속성에는 Detail 페이지로 전달하려는 데이터를 객체 형태로 설정해주면 된다. 

 

* 상세페이지에 영화 트레일러 보기 기능 추가하기

import React from 'react'
import { Movie, Button } from 'components'
import { useLocation } from 'react-router-dom'

const Detail = () => {
    const location = useLocation()
    const { movie } = location.state
    const { yt_trailer_code } = movie
    console.log(movie)

    const watchMovieTrailer = () => {
        window.location.href = yt_trailer_code? `https://www.youtube.com/watch?v=${yt_trailer_code}`: ""
    }
    return (
        <div>
            <Movie title={movie.title} 
                    genres={movie.genres} 
                    cover={movie.medium_cover_image} 
                    summary={movie.summary}
                    year={movie.year}>    
            </Movie>

            <p>{movie.summary}</p>
            <Button handleClick={watchMovieTrailer}>Watch Youtube trailer</Button>
        </div>
    )
}
export default Detail

Detail.js 파일을 위와 같이 수정하자! 

import { Movie, Button } from 'components'

Button 컴포넌트를 추가한다. 

const { yt_trailer_code } = movie

movie 데이터에서 yt_trailer_code 를 조회한다. 해당 프로퍼티는 유튜브 영상에 대한 코드이다.

const watchMovieTrailer = () => {
    window.location.href = yt_trailer_code? `https://www.youtube.com/watch?v=${yt_trailer_code}`: ""
}

 유튜브 트레일러 보기 버튼을 클릭하면 실행되는 이벤트핸들러 함수이다. 버튼을 클릭하면 yt_trailer_code 가 있으면 유튜브 트레일러를 보여주고, 없으면 Detail 페이지를 리렌더링한다. window.location.href 는 브라우저 API 이며, 외부링크로 이동할때 사용한다. 

 

* 영화 토렌트 다운로드 기능 추가하기

import React from 'react'
import { Movie, Button } from 'components'
import { useLocation } from 'react-router-dom'

const Detail = () => {
    const location = useLocation()
    const { movie } = location.state
    const { yt_trailer_code } = movie
    console.log(movie)

    const watchMovieTrailer = () => {
        window.location.href = yt_trailer_code? `https://www.youtube.com/watch?v=${yt_trailer_code}`: ""
    }
    return (
        <div>
            <Movie title={movie.title} 
                    genres={movie.genres} 
                    cover={movie.medium_cover_image} 
                    summary={movie.summary}
                    year={movie.year}>    
            </Movie>

            <p>Runtime {movie.runtime} min.</p>

            <span>Summary</span>
            <p>{movie.summary}</p>
            <a href={movie.torrents.length !== 0 ? movie.torrents[0].url : ''} download>Download Torrent</a><br/>
            <Button handleClick={watchMovieTrailer}>Watch Youtube trailer</Button>
        </div>
    )
}
export default Detail

Detail.js 파일을 위와 같이 수정하자!

<a href={movie.torrents.length !== 0 ? movie.torrents[0].url : ''} download>Download Torrent</a><br/>

movie 데이터의 torrents 프로퍼티는 배열이며 첫번째 요소의 url 에 접근하면 해당 토렌트를 다운로드 할 수 있다. a 링크의 download 속성을 설정하면 다운로드 가능하다. 

 

* 상세페이지 디자인하기

import React from 'react'
import { Movie, Button } from 'components'
import { useLocation } from 'react-router-dom'

import './Detail.css'

const Detail = () => {
    const location = useLocation()
    const { movie } = location.state
    const { yt_trailer_code } = movie
    console.log(movie)

    const watchMovieTrailer = () => {
        window.location.href = yt_trailer_code? `https://www.youtube.com/watch?v=${yt_trailer_code}`: ""
    }
    return (
        <div className='Detail-container'>
            <div className='Detail-contents'>
                <Movie title={movie.title} 
                        genres={movie.genres} 
                        cover={movie.medium_cover_image} 
                        summary={movie.summary}
                        year={movie.year}>    
                </Movie>

                <div className='Movie-info'>
                    <p className='Movie-runtime'>Runtime {movie.runtime} min.</p>
                    <p className='Movie-summary'>{movie.summary}</p>
                    <a href={movie.torrents.length !== 0 ? movie.torrents[0].url : ''} download>Download Torrent</a><br/>
                    <Button handleClick={watchMovieTrailer}>Watch Youtube trailer</Button>
                </div>
            </div>
        </div>
    )
}
export default Detail

Detail.js 파일을 위와 같이 수정하자! 

import './Detail.css'

상세페이지에 대한 스타일 코드를 추가한다. 

<div className='Detail-container'>
    <div className='Detail-contents'>
        <Movie title={movie.title} 
                genres={movie.genres} 
                cover={movie.medium_cover_image} 
                summary={movie.summary}
                year={movie.year}>    
        </Movie>

        <div className='Movie-info'>
            <p className='Movie-runtime'>Runtime {movie.runtime} min.</p>
            <p className='Movie-summary'>{movie.summary}</p>
            <a href={movie.torrents.length !== 0 ? movie.torrents[0].url : ''} download>Download Torrent</a><br/>
            <Button handleClick={watchMovieTrailer}>Watch Youtube trailer</Button>
        </div>
    </div>
</div>

상세페이지에 스타일을 적용하기 위하여 클래스명을 추가하고 div 요소를 사용하여 레이아웃을 적용하였다. 

.Detail-container{
    background: url('../assets/images/background.jpg');
    width: 100%;
    height: 100vh;

    display: flex;
    justify-content: center;
    align-items: center;
}
.Detail-contents{
    padding-top: 10px;
    padding-top: 10px;
    width: 60%;
    height: 500px;

    color: #a9a9a9;
    text-align: center;
    box-shadow: rgba(255, 255, 255, 0.35) 0px 2px 10px;

    display: flex;
    justify-content: center;
    align-items: center;
}
.Movie-info {
    padding: 15px;
    height: 100%;
    box-sizing: border-box;
    flex: 1;

    display: flex;
    flex-direction: column;
}
.Movie-info a{
    text-decoration: none;
    color: #a9a9a9;
    font-weight: bold;
}
.Movie-info a:hover{
    color: lightsalmon;
}
.Movie-runtime {
    text-align: left;
    font-weight: bold;
    font-size: 1.2rem;
}
.Movie-summary{
    flex: 1;
    overflow: auto;
    text-align: left;
    line-height: 25px;
    letter-spacing: 2px;
    font-family: tahoma;
}
.Movie-summary::-webkit-scrollbar {
    width: 10px;
    border-radius: 3px;
  }
.Movie-summary::-webkit-scrollbar-thumb {
    background-color: #a9a9a9;
    border-radius: 10px;
}
.Movie-summary::-webkit-scrollbar-track {
    background-color: lightgray;
    border-radius: 10px;
    box-shadow: inset 0px 0px 10px lightgray;
}

pages 폴더에 Detail.css 파일을 위와 같이 추가하자!

 

* 상세페이지 화면 

상세페이지 화면

 

 

728x90