Boiler Plate (1~3강)
설치
1.
더 빠르게 개발을 완성하기 위해서
3.
npm install로 dependencies 다운받기
•
Visual Studio 설치 필요
MongoDB
1.
몽고 db 회원가입
2.
몽고 db 공홈에서 클러스터 만들기
•
클라우드 상에서 만드는것
•
싱가포르 프리 티어로 할것
3.
유저 만들기
•
CONNECT 눌러서 유저 생성
•
connect your application
•
연결 코드 복사
4.
몽고 db 연결 코드 작성
•
dev.js 만들고 연결 코드를 붙여넣는다.
•
passwrod랑 dbname 부분 잘 치환해서 작성
실행
npm run dev 하면 실행된다!
안되는 경우 5000 또는 3000번 포트로 다른 서버가 열려있는지 확인해볼것
비디오 업로드 폼 만들기 (4~5강)
1.
Upload Page 만들기
•
VideoUploadPage.js 파일 생성
2.
Upload Page Route 만들기
•
true : 로그인한 사람만 들어갈수있는 페이지
•
false : 로그인안한 사람만 들어갈수있는 페이지
•
null : 아무나 들어갈수있는 페이지
<Route exact path="/video/upload" component={Auth(VideoUploadPage, true)} />
JavaScript
복사
3.
Upload Page Header Tab 만들기
•
로그인이 되어있을 경우에만 뜨도록 변경
•
(user.userData && !user.userData.isAuth) 사용
<Menu.Item key="upload">
<a href="/video/upload">video</a>
</Menu.Item>
JavaScript
복사
4.
Form Template 만들기
•
영상에서 주어지는 UI 그대로 구현
<div style={{ maxWidth: '700px', margin: '2rem auto' }}>
<div style={{ textAlign: 'center', marginBottom: '2rem' }}>
<Title level={2} > Upload Video</Title>
</div>
<Form onSubmit={onSubmit}>
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
{/* Drop zone */}
{/* Thumbnail */}
<div>
<img src alt/>
</div>
</div>
<br />
<br />
<label>Title</label>
<Input
onChange
value
/>
<br />
<br />
<label>Description</label>
<TextArea
onChange
value
/>
<br />
<br />
<select onChange>
<option key value></option>
</select>
<br />
<br />
<select onChange>
<option key value></option>
</select>
<br /><br />
<Button type="primary" size="large" onClick>
Submit
</Button>
</Form>
</div>
JavaScript
복사
5.
파일을 올리는 Template 만들기 위해 Drop-zone 다운받기
•
클라이언트 폴더에 다운받아야하는거 주의!
•
npm install react-dropzone —save
<Dropzone
onDrop
multiple
maxSize
>
{({ getRootProps, getInputProps }) => (
<div style={{ width: '300px', height: '240px', border: '1px solid lightgray', alignItems: 'center', justifyContent: 'center' }} {...getRootProps()}>
<input {...getInputProps()} />
<Icon type="plus" style={{ fontSize: '3rem' }} />
</div>
)}
</Dropzone>
JavaScript
복사
6.
onChange func 만들기
•
state 에 value를 넣어두고 서버에 한꺼번에 보낸다.
•
useState 로 초기값 정함
const [VideoTitle, setVideioTitle] = useState("");
const [Description, setDescription] = useState("");
const [private, setPrivate] = useState(0)
const [Categories, setCategories] = useState("Film & Animation")
JavaScript
복사
•
카테고리 및 private 설정은 옵션태그 여러개를 만들어야한다. map으로 깔끔하게 해결
const PrivateOption = [
{ value: 0, label: 'Private' },
{ value: 1, label: 'Public' }
]
JavaScript
복사
{PrivateOption .map((item, index) => (
<option key={index} value={item.value}>{item.label}</option>
))}
JavaScript
복사
•
위와 같은 방법으로 카테고리도 옵션 태그 여러개를 깔끔하게 쓸수있다.
•
입력칸은 onChange를 통해서 실시간으로 값을 업데이트해주지 않으면 작동하지 않는다.
const onTitleChange = (event) => {
setTitle(event.currentTarget.value)
}
JavaScript
복사
onChange={handleChangeTitle}
value={title}
JavaScript
복사
•
다른 입력태그에 대해서도 onChange일 경우에 대한 함수를 만들고 속성값으로 추가해준다.
디테일 비디오 페이지에 Side 비디오 생성
a.
Side Video 부분 Layout template 만들기
•
SideVideo라는 컴포넌트를 따로 만든다.
b.
한개의 카드 template 만들기
<div key={index} style={{ display: 'flex', marginTop: '1rem', padding: '0 2rem' }}>
<div style={{ width: '40%', marginRight: '1rem' }}>
<a href={`/video/${video._id}`} style={{ color: 'gray' }}>
<img style={{ width: '100%', height: '100%' }} src={`http://localhost:5000/${video.thumbnail}`} alt="thumbnail" />
</a>
</div>
<div style={{ width: '50%' }}>
<a href={`/video/${video._id}`} style={{ color: 'gray' }}>
<span style={{ fontSize: '1rem', color: 'black' }}>{video.title} </span><br />
<span>{video.writer.name}</span><br />
<span>{video.views}</span><br />
<span>{minutes} : {seconds}</span><br />
</a>
</div>
</div>
JavaScript
복사
•
index를 key로 넣어줘야 에러가 나지 않는다.
c.
DB에서 모든 비디오 데이터를 불러오기
•
랜딩 페이지에서 썼던것 그대로 활용
d.
불러온 데이터 화면에 출력하기
const renderSideVideo = sideVideos.map((video, index) => {
//여기에 template을 넣어서 출력
}
JavaScript
복사
구독기능
a.
Subscriber Model 만들기
•
userTo, userFrom 로 구독자수를 센다.
const subscriberSchema = mongoose.Schema({
userTo: {
type: Schema.Types.ObjectId,
ref: 'User'
},
userFrom: {
type: Schema.Types.ObjectId,
ref: 'User'
}
}, { timestamps: true })
JavaScript
복사
b.
Subscribe Button UI 만들기
•
구독 컴포넌트를 따로 만든다.
<div>
<button
style={{
backgroundColor: '#CC0000',
borderRadius: '4px', color: 'white',
padding: '10px 16px', fontWeight: '500', fontSize: '1rem', textTransform: 'uppercase'
}}
onClick>
0 Subscribe
</button>
</div>
JavaScript
복사
c.
데이터베이스에서 얼마나 많은 사람이 비디오 업로드 한 유저를 구독하는지 정보 가져오기
•
디테일 페이지에서 actions={[<Subscribe userTo={video.writer._id} />]} 이렇게 넘겨주면
•
props.userTo로 정보를 받아올수있다. 아래와 같이 구독자수를 요청한다.
let variable = { userTo: props.userTo }
Axios.post('/api/subscribe/subscribeNumber', variable)
.then( response => {
if (response.data.success) {
} else {
alert('구독자 수 정보를 받아오지 못했습니다.')
}
})
JavaScript
복사
•
서버에서 /api/subscribe/subscribeNumber 라우터를 만들어야한다
•
index.js에서 /api/subscribe 라우터를 연결해준다.
router.post('/subscribeNumber', (req, res) => {
Subscriber.find({ 'userTo' : req.body.userTo})
.exec((err, subscribe) => {
if (err) return res.status(400).send(err)
return res.status(200).json({ success: true, subscribeNumber: subscribe.length })
})
})
JavaScript
복사
•
length로 구독자수를 센다.
d.
내가 이 비디오 업로드 한 유저를 구독하는지 정보 가져오기
•
userFrom은 localstorage에 있다. 아래와 같이 구독 여부를 요청한다.
let subscribedVariable = { userTo: props.userTo, userFrom : localStorage.getItem('usetId')}
Axios.post('/api/subscribe/subscribed', subscribedVariable)
.then(response => {
if (response.data.success) {
setSubscribed(response.data.Subscribed)
} else {
alert('정보를 받아오지 못했습니다.')
}
})
}, [])
JavaScript
복사
•
서버에서 /api/subscribe/subscribed 라우터를 만든다.
router.post('/subscribed', (req, res) => {
Subscriber.find({ 'userTo' : req.body.userTo, 'userFrom' : req.body.userFrom})
.exec((err, subscribe) => {
if (err) return res.status(400).send(err)
let result = false;
if (subscribe.length !== 0)
result = true
res.status(200).json({ success: true, subscribed: result })
})
})
JavaScript
복사
e.
가져온 정보들 화면에 출력
{SubscribeNumber} {Subscribed ? 'Subscribed' : 'Subscribe'}
JavaScript
복사
f.
구독하기/구독취소 기능 만들기
•
클라이언트에서 구독 여부에 따라 구독또는 취소 요청을 한다.
const onSubscribe = () => {
let subscribedVariable = { userTo: props.userTo, userFrom: props.userFrom }
if (Subscribed) {
Axios.post('/api/subscribe/unSubscribe', subscribedVariable)
.then(response => {
if (response.data.success) {
setSubscribeNumber(SubscribeNumber - 1)
setSubscribed(!Subscribed)
} else {
alert('구독 취소 실패')
}
})
} else {
Axios.post('/api/subscribe/Subscribe', subscribedVariable)
.then(response => {
if (response.data.success) {
setSubscribeNumber(SubscribeNumber + 1)
setSubscribed(!Subscribed)
} else {
alert('구독 실패')
}
})
}
}
JavaScript
복사
•
서버에서 해당 라우터들을 만든다.
router.post('/unSubscribe', (req, res) => {
Subscriber.findOneAndDelete({ 'userTo': req.body.userTo, 'userFrom': req.body.userFrom})
.exec((err, doc) => {
if (err) return res.status(400).json({success:false, err})
return res.status(200).json({ success: true, doc})
})
})
JavaScript
복사
•
구독취소는 findOneAndDelete를 이용해서 db에서 삭제한다.
router.post('/Subscribe', (req, res) => {
const subscribe = new Subscriber(req.body)
subscribe.save((err, doc) => {
if (err) return res.status(400).json({ success: false, err })
return res.status(200).json({ success: true})
})
})
JavaScript
복사
•
구독은 save를 통해서 db에 값을 넣는다.
•
영상 업로더는 자기자신을 구독 못하게 해야한다.
const subscribeButton = videoDetail.writer._id !== localStorage.getItem('usetId') && <Subscribe userTo={videoDetail.writer._id} userFrom={localStorage.getItem('usetId')} />
JavaScript
복사
구독 비디오 페이지
a.
빈 Subscription 페이지 생성
b.
Subscription Page를 위한 Route 만들기
•
app.js 수정해서 route 만든다.
<Route exact path="/subscription" component={Auth(SubscriptionPage, null)} />
JavaScript
복사
c.
Template 만들기
•
랜딩페이지를 거의 그대로 가져온다.
•
subcription 페이지를 탭에 올린다.
<Menu.Item key="subscription">
<a href="/subscription">Subscription</a>
</Menu.Item>
JavaScript
복사
d.
내가 구독한 유저의 비디오들만 서버에서 가져오기
•
/api/video/getSubscriptionVideos 로 구독한 영상만 요청 (userFrom 사용)
let variable = { userFrom: localStorage.getItem('userId') }
useEffect(() => {
axios.post('/api/video/getSubscriptionVideos', variable)
.then(response => {
if (response.data.success) {
setVideos(response.data.videos)
} else {
alert('Failed to get subscription videos')
}
})
}, [])
JavaScript
복사
•
서버에서 라우터 생성
•
자신의 아이디를 가지고 구독하는 사람들을 찾는다.
Subscriber.find({ 'userFrom': req.body.userFrom })
.exec((err, subscribers) => {
if (err) return res.status(400).send(err);
let subscribedUser = [];
subscribers.map((subscriber, i) => {
subscribedUser.push(subscriber.userTo)
})
//subscribedUser에 구독하는 사람들이 있다.
JavaScript
복사
•
찾은 사람들의 비디오를 가지고 온다.
•
구독한 사람이 여러명이기때문에 in이라는 메소드를 사용한다.
•
몽고db 내부함수인 in을 통해서 한번에 여러명의 결과를 가져올수있다.
Video.find({ writer: { $in: subscribedUser } })
.populate('writer')
.exec((err, videos) => {
if (err) return res.status(400).send(err);
res.status(200).json({ success: true, videos })
})
JavaScript
복사
e.
가져온 비디오 데이터들을 화면에 출력하기
댓글 기능 생성 - 구조 설명
a.
댓글 부분 구조 설명
•
댓글을 달수 있다.
•
댓글에 답글을 달 수 있다.
•
답글에도 무한하게 답글을 달 수 있다.
b.
Commet model 생성
•
writer, videoid, content, replayTo 4가지 가 필요하다
const commentSchema = mongoose.Schema({
writer: {
type: Schema.Types.ObjectId,
ref: 'User'
},
postId: {
type: Schema.Types.ObjectId,
ref: 'Video'
},
responseTo: {
type: Schema.Types.ObjectId,
ref: 'User'
},
content: {
type: String
}
}, { timestamps: true })
JavaScript
복사
c.
디테일 비디오 페이지에 Commet Component 만들기
댓글 기능 생성 - Comment.js
a.
template 만들기
b.
handleChange func 만들기
const handleClick = (e) => {
setComment(e.currentTarget.value)
}
JavaScript
복사
c.
OnSubmit func 만들기
•
기존 동작 안하게 prevent 해준다.
•
props로 postId를 받아온다.
•
writer를 위해서 redux hook를 사용한다.
const user = useSelector(state => state.user)
JavaScript
복사
•
/api/comment/saveComment 로 요청한다.
•
서버에서 라우터를 만든다. index.js에서 comment 라우터 연결 해준다.
router.post("/saveComment", (req, res) => {
const comment = new Comment(req.body)
comment.save((err, comment) => {
if (err) return res.json({ success: false, err })
Comment.find({ '_id': comment._id })
.populate('writer')
.exec((err, result) => {
if (err) return res.json({ success: false, err })
return res.status(200).json({ success: true, result })
})
})
})
JavaScript
복사
axios.post('/api/comment/saveComment', variables)
.then(response => {
if (response.data.success) {
console.log(response.data.result)
} else {
alert('코맨트를 저장하지 못했습니다.')
}
})
JavaScript
복사
•
서버에서 받아온 Comment내용을 콘솔에서 확인
d.
이때 추가하고 나면 comment state를 업데이트 해줘야함