-
Youtube 만들기 - 7) 비디오 디테일 페이지 만들기NODE.JS 2021. 5. 14. 18:43
랜딩페이지에서 비디오 하나를 클릭하면
하나의 비디오에 해당하는 디테일 페이지를 생성하도록 만든다.
제일먼저 비디오 디테일 페이지를 만들어준다.
src>components>views>VideoDetailPage>VideoDetailPage.js를 생성해준다.
그리고 만든 페이지를 app.js에서 추가해준다.
링크는 개별의 videoId를 이용해서 들어오도록 설정하고 아무나 볼 수 있도록 null로 넣어준다.
import React, { Suspense } from 'react'; import { Route, Switch } from "react-router-dom"; import Auth from "../hoc/auth"; // pages for this product import LandingPage from "./views/LandingPage/LandingPage.js"; import LoginPage from "./views/LoginPage/LoginPage.js"; import RegisterPage from "./views/RegisterPage/RegisterPage.js"; import NavBar from "./views/NavBar/NavBar"; import Footer from "./views/Footer/Footer" import VideoUploadPage from "./views/VideoUploadPage/VideoUploadPage"; import VideoDetailPage from "./views/VideoDatailPage/VideoDetailPage"; //null Anyone Can go inside //true only logged in user can go inside //false logged in user can't go inside function App() { return ( <Suspense fallback={(<div>Loading...</div>)}> <NavBar /> <div style={{ paddingTop: '69px', minHeight: 'calc(100vh - 80px)' }}> <Switch> <Route exact path="/" component={Auth(LandingPage, null)} /> <Route exact path="/login" component={Auth(LoginPage, false)} /> <Route exact path="/register" component={Auth(RegisterPage, false)} /> <Route exact path="/video/upload" component={Auth(VideoUploadPage, true)} /> <Route exact path="/video/:videoId" component={Auth(VideoDetailPage, null)} /> </Switch> </div> <Footer /> </Suspense> ); } export default App;
비디오 디테일 페이지를 만드는데,
이 디테일 페이지는 어느정도 화면크기가 줄어들면 사이드의 동영상 리스트들이 화면 아래로 이동하는 모습을 나타낸다.
Row, Col을 이용해서 반응형으로 만든다.
(antd 이용)
import React, {useEffect, useState}from 'react' import {Row, Col, List, Avatar} from 'antd'; import Axios from 'axios'; import {response} from 'express'; import SideVideo from './Sections/SideVideo'; import Subscribe from './Sections/Subscribe'; function VideoDetailPage(props) { return ( <Row gutter={[16, 16]}> <Col lg = {18} xs = {24}> <div tyle = {{ width:'100%', padding = '3rem 4rem' }}>//동영상 나타내는 부분 <video style = {{width:'100%' }}src={`http:/localhost:5000/${VideoDetail.filePath}`} controls /> <List.Item//동영상 만든사람의 정보를 나타내는 부분 actions//좋아요와 싫어요 버튼 > <List.Item.Meta avatar = {<Avatar src={VideoDetail.writer.image}/>}//유저의 이미지(populate해서 가능하다) title = {VideoDetail.writer.name} description = {VideoDetail.description} /> </List.Item> {/* Comments */} </div> </Col> <Col lg = {6} xs={24}> <SideVideo /> </Col> </Row> ) export default VideoDetailPage
비디오 랜딩페이지에가서 랜딩페이지에서 동영상을 누르면 링크로 들어오도록 설정했었다.
{/* 하나의 동영상에 해당하는 페이지로 이동 */} <a href={`/video/post/${video._id}`}>
다시 디테일 페이지로 돌아와서
비디오에 대한 정보를 요청하는 axios를 만들어주자.
function VideoDetailPage(props) { const videoId =props.match.params.videoId//app.js에서 루트로 :videoId 보냈기 때문에 가져올 수 있다. const variable = {videoId: videoId} const [VideoDetail, setVideoDetail] = useState([]) useEffect(() => { Axios.post('/api/video/getDetailVideo', variable) .then(response =>{ if(response.data.success){ setVideoDetail(response.data.videoDetail) }else{ alert('비디오 정보를 가져오길 실패했습니다.') } }) }, [])
video.js에서 라우트를 생성해준다.
아이디를 이용해서 맞는 비디오 디테일을 가져온다.
router.post('/getDetailVideo', (req, res)=>{ Video.findOne({"_id":req.body.videoId}) //비디오를 찾아온다. .populate('writer')//populate를 해줘야 user관련 데이터를 가져올수 있다. 안하면 id만 가져온다. .exec((err, videoDetail)=>{ if(err)return res.status(400).send(err); res.status(200).json({success:true,videoDetail}) }) })
여기서 비디오 writer가 있어야지만 코드르 렌더링 할 수 있도록 바꿔준다.
(가져오지 않은 상태에서 먼저 실행될 수 있으므로)
import React, {useEffect, useState}from 'react' import {Row, Col, List, Avatar} from 'antd'; import Axios from 'axios'; import {response} from 'express'; import SideVideo from './Sections/SideVideo'; import Subscribe from './Sections/Subscribe'; function VideoDetailPage(props) { const videoId =props.match.params.videoId//app.js에서 :videoId 보냈기 때문에 가져올 수 있다. const variable = {videoId: videoId} const [VideoDetail, setVideoDetail] = useState([]) useEffect(() => { Axios.post('/api/video/getVideoDetail', variable) .then(response =>{ if(response.data.success){ setVideoDetail(response.data.videoDetail) }else{ alert('비디오 정보를 가져오길 실패했습니다.') } }) }, []) if(VideoDetail.writer){ return ( <Row gutter={[16, 16]}> <Col lg = {18} xs = {24}> <div tyle = {{ width:'100%', padding = '3rem 4rem' }}> <video style = {{width:'100%' }}src={`http:/localhost:5000/${VideoDetail.filePath}`} controls /> <List.Item actions ={[<Subscribe userTo = {VideoDetail.writer._id} userFrom= {localStorage.getItem('userId')}/>]}//여기서 userTO 보내주면 Subscribe에서 prop으로 받아서 사용가능하다. > <List.Item.Meta avatar = {<Avatar src={VideoDetail.writer.image}/>} title = {VideoDetail.writer.name} description = {VideoDetail.description} /> </List.Item> {/* Comments */} </div> </Col> <Col lg = {6} xs={24}> <SideVideo /> </Col> </Row> ) } else { return ( <div>...loading</div> ) } } export default VideoDetailPage
이번에는 옆에 보이는 side 비디오를 생성해보자.
views>VideoDetailPage>Sections>SideVideo.js를 만들어준다.
왼쪽에는 이미지 오른쪽에는 정보가 올 수 있도록 만들 것이다.
우선, 하나의 카드에 적용되는 return을 만들어보자.
import React ,{useEffect, useState} from 'react' import Axios from 'axios'; function SideVideo() { return ( <div key = {index} style={{display: 'flex', marginBottom:'1rem', padding:'0 2rem'}}> //왼쪽 이미지 가져오는 부분 <div style ={{width:'40%', marginRight:'1rem'}}> <a href> <img style = {{ width:'100%', height:'100%'}}src={`http://localhost:5000/${video.thumbnail}`} alt="thumbnail"/> </a> </div> //오른쪽 동영상 정보 가져오는 부분 <div style = {{width:'50%'}}> <a href style={{color:'gray'}}> <span style={{fontSize:'1rem', color:'black'}}>{videoTitle}</span> <span>{video.writer.name}</span><br /> <span>{video.views} views </span><br /> <span>{minutes} : {seconds}</span><br /> </a> </div> </React.Fragment> ) } export default SideVideo
db에서 데이터 베이스를 가져오자 .
useEffect 를 사용할 것이다.
랜딩페이지에서 동영상을 불러올때 모든 동영상을 불러오는 api를 이미 작성해뒀다.
이를 이용해서 동영상을 나타낼 것이다.
function SideVideo() { const [sideVideos, setsideVideos] = useState([])//state이름만 바꿔서 가져와서 저장한다. useEffect(() => { Axios.get('/api/video/getVideos') .then(response =>{ if(response.data.success){ setsideVideos(response.data.videos) } else{ alert('비디오 가져오기를 실패 했습니다.') } }) }, [])
우리는 하나의 카드가 아닌 여러개의 동영상에 대해서 특징을 적용하므로 이를 map을 이용해서 나타나도록 지정해보자.
import React ,{useEffect, useState} from 'react' import Axios from 'axios'; function SideVideo() { const [sideVideos, setsideVideos] = useState([]) useEffect(() => { Axios.get('/api/video/getVideos') .then(response =>{ if(response.data.success){ setsideVideos(response.data.videos) } else{ alert('비디오 가져오기를 실패 했습니다.') } }) }, []) const renderSideVideo = sideVideos.map((video, index)=>{ var minutes = Math.floor(video.duration/60); var seconds = Math.floor((video.duration - minutes*60)); //map은 index를 키로 넣어줘야 에러가 생기지 않는다. return <div key = {index} style={{display: 'flex', marginBottom:'1rem', padding:'0 2rem'}}> <div style ={{width:'40%', marginRight:'1rem'}}> <a href> <img style = {{ width:'100%', height:'100%'}}src={`http://localhost:5000/${video.thumbnail}`} alt="thumbnail"/> </a> </div> <div style = {{width:'50%'}}> <a href style={{color:'gray'}}> <span style={{fontSize:'1rem', color:'black'}}>{videoTitle}</span> <span>{video.writer.name}</span><br /> <span>{video.views} views </span><br /> <span>{minutes} : {seconds}</span><br /> </a> </div> </div> }) return ( <React.Fragment> <div style={{marginTop:'3rem'}}></div> {renderSideVideo} </React.Fragment> ) } export default SideVideo
'NODE.JS' 카테고리의 다른 글
Youtube 만들기 - 9) 구독 비디오 페이지 만들기 (0) 2021.05.14 Youtube 만들기 - 8) 구독기능 만들기 (0) 2021.05.14 Youtube 만들기 - 6) 랜딩페이지에 비디오들 나타내기 (0) 2021.05.14 Youtube 만들기 - 5) 비디오 업로드 Form 만들기 4(비디오 업로드 하기) (0) 2021.05.14 Youtube 만들기 - 4) 비디오 업로드 Form 만들기 3(썸네일 만들기) (0) 2021.05.14