axios를 이용한 client(react)-server(node) 통신방법을 예제를 통해 익혀보았다.
여러 예제를 통한 통신방법의 숙달을 목표로 하였다.
John ahn의 노드 / 리액트 시리즈를 공부하며 작성하였다.
Promis API를 이용한 http 비동기 통신 라이브러리이다.
- get => Axios.get('url')
- post => Axios.post('url', data 객체)
post의 경우 두 번째 인자로 서버로 보낼 data 객체 리터럴을 입력한다.
MongoDB에서는 데이터가 차곡차곡 쌓일 때, 그 데이터 하나하나를 document라고 한다.
- 스키마 : 해당 컬렉션의 document에 어떤 타입의 데이터가 들어갈지 정의하는 것.
- 모델 : 스키마를 통해 인스턴스 객체를 만들어 이를 활용해 DB에서 실제 작업을 할 수 있게 해줌.
스키마를 정의할 때 다음과 같이 옵션을 줄 수 있다.
- timestamp => createdAt, updatedAt 필드를 자동 생성한다.
const schema = mongoose.Schema({ name: String }, { timestamp: true })
- id => default로 _id 필드를 자동 생성하는데, 이를 취소할 수 있다.
const schema = mongoose.Schema({ name: String }, { id: false })
MongoDB 스키마를 만들다 보면, 다른 다큐먼트의 ObjectID를 쓰는 경우가 있다.
writer: { type: Schema.Types.ObjectId, ref: 'User', }
다른 document들 끼리 서로 참조할 수 있도록 type옵션을 정의하고, ref옵션을 통해 참조할 모델을 정의한다.
위의 경우 User모델의 document를 참조할 수 있다..populate('writer')
populate 메소드를 이용해 'User' 도큐먼트를 가져올 수 있다.
- exec
- exec메서드를 통해 온전한 프로미스를 반환할 수 있다.
에러가 발생했을 때 추적이 가능하므로 사용하는 것이 좋다.- find
- .find() 모두 찾음.
- .find({ name: 'kim' }) 해당 키 값을 가진 도큐먼트를 찾음.
- .find({ $in: name }) name배열에 담긴 모든 값을 가진 도큐먼트를 찾음.
router의 파라미터 정보를 가져와 사용하고 싶을 때 useParams 훅을 사용한다.
사용법
npm i react-router-dom
로 react-router-dom 설치
- 경로가 URL/pathname/1 일때, 1이 params이다.
import { useParmas } from 'react-router-dom' const { params } = useParams() console.log(parmas)
params 1이 출력된다.
브라우저에 특정 데이터를 저장하기 위해 사용하는 웹 스토리지의 종류이다.
localStorage는 sessionStorage와 다르게 브라우저를 닫고, 새탭을 열어도 데이터가 그대로 남아있는 특징(영속성)이 있다.//키, 값 데이터 저장 localStorage.setItem('key', 'value') //키, 값 데이터 불러오기 localStorage.getItem('key')
e.preventDefault()는 두 가지 기능이 있다.
- a태그를 눌렀을 때, 새 창으로 넘어가지 않게 해준다.
- submit버튼을 눌렀을 때, submit은 작동되지만 새로고침 되지 않게 해준다.
const onSubmit = e => e.preventDefault()
비디오를 웹에 업로드 하기 위해 비디오 데이터를 다룬다.
비디오 데이터를 mongoDB에 저장하기 위해 Video 모델을 생성한다.
writer에서 User(사용자 정보) 모델의 도큐먼트를 참조할 수 있도록 relation을 걸어준다.
server/models/video
import mongoose from 'mongoose'
const Schema = mongoose.Schema
const videoSchema = mongoose.Schema({
//writer 필드로 해당 User 모델의 다큐먼트를 참조할 수 있게 relation을 걸어준다.
writer: {
type: Schema.Types.ObjectId,
ref: 'User'
},
title: String,
description: String,
filePath: String,
category: String,
views: {
type: String,
default: 0,
}
duration: String,
thumbnail: String
}, { timestamps: true })
const Video = mongose.model('Video', videoSchema)
module.exports = { Video }
client에서 axios를 통해 비디오 데이터를 전송한다.
localStorage에 저장된 userId 데이터를 getItem으로 불러온다.
client
import React, { userState } from 'react'
import { Axios } from 'axios'
const onSubmit = (e) => {
//새로고침을 막아줌.
e.preventDefault()
const writer = localStorage.getItem('userId')
const variables = {
writer,
//useState에 저장된 데이터들을 넣어준다.
title,
description,
filePath,
category,
duration,
thumbnail,
}
Axios.post('/api/video/uploadVideo', variables)
.then(res => {
if(res.body.success) {
console.log(res.data.video)
} else {
console.log(res.data.err)
}
})
}
app.js에서 경로를 분기시켜준다.
server/app.js
app.use('/api/video', require('./routes/video'))
save() 함수를 이용하여 데이터를 mongoDB에 저장한다.
server/routes/video.js
import express from 'express'
const router = express.Router()
//Video 모델 불러오기.
import { Video } from '../models/Video'
router.post('/uploadVideo', (req, res, err) => {
//새로운 도큐먼트 생성.
const video = new Video(req.body)
video.save((err, video) => {
if(err) return res.json({ success: false, err })
res.status(200).json({ success: true, video })
})
})
get http 메서드를 사용해 DB에 저장시킨 비디오 데이터를 불러온다.
client
Axios.get('/api/video/getVideo')
.then(res => {
if(res.data.success) {
console.log(res.data.video)
} else {
console.log(res.data.err)
}
})
저장시킨 모든 비디오 도큐먼트 데이터들에 유저 도큐먼트를 참조하여 불러온 뒤 client에 보내준다.
server/routes/video.js
router.get('/getVideo', (res, req) => {
Video
//Video컬렉션의 전체 다큐먼트를 찾는다.
.find()
//User컬렉션의 다큐먼트를 참조한다.
.populate('writer')
.exec((err, videos) => {
if(err) return res.status(400).json({ success: false, err })
res.status(200).json({ success: true, videos })
})
})
videoId는 Video 모델에서 필드가 "_id"로 저장된 부분이며, params이다.
URL/pathname/:videoId
client
import { Axios } from 'axios'
import { useParams } from 'react-router-dom'
const { videoId } = useParams()
useEffect(() => {
const variable = { videoId }
Axios.post('/api/video/detailVideo', variable)
.then(res => {
if(res.data.success) {
console.log(res.data.detailVideo)
} else {
console.log(res.data.err)
}
})
}, [])
해당 Video 도큐먼트의 .populate('writer')를 사용해 User document를 참조형 불러온다.
server/api/routes/video.js
router.post('/detailVideo', (req, res) => {
Video
.findOne({ "_id": req.body.videoId })
.populate('writer')
.exec((err, detailVideo) => {
if(err) return res.status(400).json({ success: false, err })
res.satus(200).json({ success: true, detailVideo })
})
})
구독기능 데이터를 mongoDB에 저장하기 위해 Subscribe 모델을 생성한다.
userTo와 userFrom에서 User 모델을 참조할 수 있도록 relation을 걸어준다.
userTo는 비디오를 올린 유저의 Id이고, useFrom은 내 Id이다.
server/models/subscribe.js
import mongoose from 'mongoose'
const Schema = mongoose.Schema
const subscribeShema = mongoose.Schema({
userTo: {
type: Schema.types.ObjectId,
ref: 'User'
},
userFrom: {
type: Schema.types.ObjectId,
ref: 'User'
}
})
const Subscribe = mongoose.model('Subscribe', subscribeShema)
module.exports = { Subscribe }
localStorage에 저장된 userId 데이터를 userFrom(내 Id)에 담아준다.
isSubscribe가 true면 구독을 취소하고, false면 구독을 신청을한다.
client
import React, { useState } from 'react'
import { Axios } from 'axios'
const { videoId } = useParams()
const [ isSubscribe, setIsSubscribe ] = useState(null)
const onSubscribe = () => {
const userTo = videoId
const userFrom = localStorage.getItem('userId')
const variables = { userTo, userFrom }
//구독 신청
if(!subscribed) {
Axios.post('/api/subscribe/regSubscribe', variables)
.then(res => {
if(res.data.success) {
setIsSubscribe(true)
console.log(res.data.subscribe)
} else {
console.log(res.data.err)
}
})
//구독 취소
} else {
Axios.post('/api/subscribe/delSubscribe', variables)
.then(res => {
if(res.data.success) {
setIsSubscribe(false)
console.log(res.data.subscribe)
} else {
console.log(res.data)
}
}
}
}
app.js에서 routes해준다.
server/app.js
app.use('/api/subscribe', require('./routes/subscribe'))
server/routes/subscribe.js
//구독 신청
router.post('/regSubscribe', (req, res) => {
const subscribe = new Subscribe(req.body)
subscribe
.save((err, subscribe) => {
if(err) return res.status(400).json({ success: false, err })
res.status(200).json({ success: true, subscribe })
})
})
//구독 취소
router.post('/delSubscribe', (req, res) => {
Subscribe
.findOneAndDelete({ "userTo": req.body.userTo, "userFrom": req.body.userFrom })
.exec((err, subscribe) => {
if(err) return res.status(400).json({ success: false, err })
res.status(200).json({ success: true, subscribe })
})
})
userTo(구독 당한 유저의 _id) 데이터 갯수를 통해 구독자 수를 가져온다.
client
import React, { useState, useEffect } from 'react'
import { useParams } from 'react-router-dom'
import { Axios } from 'axios'
const { videoId } = useParams()
//구독자 수를 담을 state
const [ numSubscribe, setNumSubscribe ] = useState(0)
useEffect(() => {
const variable = { userTo: videoId }
Axios.post('api/subscribe/numSubscribe', variable)
.then(res => {
if(res.data.success) {
setNumSubscribe(res.data.numSubscribe)
} else {
console.log(res.data.err)
}
})
}, [])
server/routes/subscribe.js
import { Subscribe } from '../models/subscribe'
router.post('/numSubscribe', (req, res) => {
Subscribe
.find({ userTo: req.body.userTo })
.exec((err, subscribes) => {
if(err) return res.status(400).json({ success: false, err })
res.status(200).json({ success: true, numSubscribe: subscribes.length })
})
})
userTo(구독 당한 유저의 _id)와 userFrom(내 _id)데이터를 함께 조회해 구독여부를 판단한다.
client
import { useParams } from 'react-router-dom'
import { Axios } from 'axios'
const { videoId } = useParams()
const [ isSubscribe, setIsSubscribe ] = useState(null)
useEffect(() => {
const userTo = videoId
const useFrom = localStorage.getItem('useId')
const variables = { userTo, userFrom }
Axios.post('/api/subscribe/isSubscribe', variables)
.then(res => {
if(res.data.success) {
setIsSubscribe(res.data.isSubscribe)
} else {
console.log(res.data)
}
})
}, [])
server/routes/subscribe.js
import { Subscribe } from '../models/subscribe'
router.post('/isSubscibe', (req, res) => {
Subscribe
.findOne({ userTo: req.body.userTo, userFrom: req.body.userFrom })
.exec((err, subscribe) => {
if(err) return res.status(400).json({ success: false, err })
let isSubscribe = false
if(subscribe.length !== 0) {
isSubscribe = true
res.status(200).json({ success: true, isSubscribe })
} else {
res.status(200).json({ success: true, isSubscribe })
}
}
})
유저의 구독한 Video document 데이터들을 불러온다.
userFrom으로 내가 구독한 비디오를 불러온다.
client
import React, { useEffect } from 'react'
import { Axios } from 'axios'
const [ videos, setVideos ] = useState([])
useEffect(() => {
const userFrom = localStorage.getItem('userId')
const variable = { userFrom }
Axios.post('api/subscribe/getSubVideos', variable)
.then(res => {
if(res.data.success) {
setVideos(res.data.videos)
} else {
console.log(res.data)
}
})
})
populate 메서드로 writer로 참조하고 있는 Video컬렉션의 document들을 불러올 수 있다.
server/routes/subscribe
router.post('/getSubVideos', (req, res) => {
//pulisher배열에 useTo 필드를 담아준다.
let publisher = []
Subscribe
.find({ "userFrom": req.body.userFrom })
.exec((err, subscribes) => {
if(err) res.status(400).json({ success: false, err })
subscribes.map(subscribe => {
publisher.push(subscribe.userTo)
})
})
Video
//Video모델의 writer 필드가 userTo 값을 담은 배열과 같은 도큐먼트를 찾는다.
.find({ "writer": { $in: publisher } })
//User모델의 도큐먼트를 참조한다.
.populate('writer')
.exec((err, videos) => {
if(err) res.status(400).json({ success: true, err })
res.status(200).json({ success: true, videos })
})
})
댓글기능 데이터를 mongoDB에 저장하기 위해 Comment 모델을 생성한다.
writer는 댓글을 쓴 사람의 User 도큐먼트를 참조한다.
videoId는 비디오를 생성한 사람의 User 도큐먼트를 참조한다.
server/models/comment.js
import mongoose from 'mongoose'
const Schema = mongoose.Schema
const commentSchema = mongoose.Schema({
writer: {
type: Shema.types.ObjectId,
ref: 'User'
},
videoId: {
type: Shema.types.ObjectId,
ref: 'User'
},
comment: String
})
const Comment = mongoose.model('Comment', commentSchema)
module.exports = { Comment }
userId와 videoId를 서버로 보내 댓글을 저장한다.
client
const React from 'react'
const { useParams } from 'react-router-dom'
const writer = localStorage.getItem('userId')
const { videoId } = useParams()
const onSubmit = () => {
const variables = { writer, videoId, comment }
Axios.post('/api/comment/regComment', variables)
.then(res => {
if(res.data.success) {
console.log(res.data.comment)
} else {
console.log(res.data.err)
}
})
}
app.js에서 routes해준다.
server/app.js
app.use('/api/comment', require('/routes/comment'))
생성한 comment 도큐먼트에 User 도큐먼트를 참조하여 보내준다.
server/routes/comment.js
import express from 'express'
const router = express.Router()
import { Comment } from '../models/comment'
router.post('/regComment', (req, res) => {
const comment = new Comment(req.body)
comment.save((err, comment) => {
if(err) return res.status(400).json({ success: false, err })
Comment
.find({ "_id": comment._id })
//생성한 comment 도큐먼트의 User 도큐먼트를 참조한다.
.populate('writer')
.exec((err, comment) => {
if(err) return res.status(400).json({ success: false, err })
res.status(200).json({ success: true, comment })
})
})
})
userId, videoId, commentId 필드를 만든다.
userId는 내 Id 정보이다.
videoId가 존재할 땐 해당 비디오에 대한 좋아요 기능을,
commentId가 존재할 땐 해당 코멘트에 대한 좋아요 기능을 만든다.
좋아요, 싫어요 기능 데이터를 DB에 저장하기 위해 Like, Dislike모델을 생성한다.
server/models/like.js
import mongoose from 'mongoose'
const Schema = mongoose.Schema
const likeSchema = mongoose.Schema({
userId: {
type: Schema.types.ObjectId,
ref: 'User'
},
videoId: {
type: Schema.types.ObjectId,
ref: 'User'
},
commentId: {
type: Schema.types.ObjectId,
ref: 'User'
},
})
const Like = mongoose.model('Like', likeSchema)
exports.module = { Like }
server/models/Dislike.js
import mongoose from 'mongoose'
const Schema = mongoose.Schema
const dislikeSchema = mongoose.Schema({
userId: {
type: Schema.types.ObjectId,
ref: 'User'
},
videoId: {
type: Schema.types.ObjectId,
ref: 'User'
},
commentId: {
type: Schema.types.ObjectId,
ref: 'User'
},
})
const Dislike = mongoose.model('Dislike', dislikeSchema)
exports.module = { Dislike }
비디오에 대한 좋아요, 싫어요 기능 과 코멘트에 대한 좋아요, 싫어요 기능을 나누기
- DB에 좋아요, 싫어요 갯수가 몇개인지
- 좋아요, 싫어요 중 하나를 이미 내가 눌렀는지에 대한 데이터를 가져온다.
client
const LikeAndDislike = (props) => {
//생략...
const [numLike, setNumLike] = useState(0)
const [isLiked, setIsLiked] = useState(false)
const [numDislike, setNumDislike] = useState(0)
const [isDisliked, setIsDisliked] = useState(false)
useEffect(() => {
const userId = localStorage.getItem('userId')
//비디오와 코멘트의 좋아요, 싫어요 데이터 나누기
let variable = {}
if(props.videoId) {
variables = { videoId: props.videoId }
} else if(props.commentId) {
variables = { commentId: props.commentId }
}
//좋아요 관련 데이터 불러오기
Axios.post('/api/like/getLike', variables)
.then(res => {
if(res.data.success) {
const { likes } = res.data
//좋아요 갯수
setNumLike(likes.length)
//좋아요를 눌렀는지 여부
likes.forEach(like => {
if(like.userId === userId) return setIsLiked(true)
})
} else {
console.log(res.data)
}
})
//싫어요 관련 데이터
Axios.post('/api/like/getDislike', variables)
.then(res => {
if(res.data.success) {
const { dislikes } = res.data
//싫어요 갯수
setNumDislike(dislikes.length)
//싫어요를 눌렀는지 여부
dislikes.forEach(dislike => {
if(dislike.userId === userId) return setIsDisliked(true)
})
} else {
console.log(res.data)
}
})
},[])
}
server/app.js
app.use('/app/like', require('./routes/like')
server/routes/like.js
import { Like } from '../../models/Like'
import { Dislike } from '../../models/Dislike'
router.post('/getLike', (req, res) => {
//비디오와 코멘트의 좋아요 데이터 나누기
let variable = {}
if(req.body.videoId) {
variable = { videoId: req.body.videoId }
} else if(req.body.commentId) {
variable = { commentId: req.body.commentId }
}
//좋아요 데이터 보내기
Like
.find(variable)
.exec((err, likes) => {
if(err) return res.status(400).json({ success: false, err })
res.status(200).json({ success: true, likes })
})
})
router.post('/getDislike', (req, res) => {
//비디오와 코멘트의 좋아요 데이터 나누기
let variable = { }
if(req.body.videoId) {
variable = { videoId: req.body.videoId }
} else if(req.body.commentId) {
variable = { commentId: req.body.commentId }
}
//싫어요 데이터 보내기
Dislike
.find(variable)
.exec((err, dislikes) => {
if(err) return res.status(400).json({ success: false, err })
res.status(200).json({ success: true, dislikes })
})
})
비디오에 대한 좋아요, 싫어요 기능 과 코멘트에 대한 좋아요, 싫어요 기능을 나누기
- 좋아요가 되어있을 때, 싫어요를 누르면 => 좋아요 취소, 싫어요 체크
- 싫어요가 되어있을 때, 좋아요를 누르면 => 싫어요 취소, 좋아요 체크
- 좋아요가 되어있을 때, 좋아요를 누르면 좋아요 취소
- 싫어요가 되어있을 때, 싫어요를 누르면 싫어요 취소
client
//좋아요 누르기
const onClickLike = () => {
//비디오와 코멘트의 좋아요 데이터 나누기
let variables = {}
if(props.videoId) {
variables = { userId, videoId: props.videoId }
} else if(props.commentId) {
variables = { userId, commentId: props.commentId }
}
//좋아요가 안눌려져 있을 때 좋아요 데이터 등록
if(isLiked === false) {
Axios.post('/api/like/regLike', variables)
.then(res => {
if(res.data.success) {
//좋아요 여부를 true로, 좋아요 갯수를 1 추가.
setIsLiked(true)
setNumLike(numLike + 1)
if(isDisliked === true) {
setIsDisliked(false)
setNumDislike(numDislike - 1)
}
} else {
console.log(res.data)
}
})
}
//좋아요가 눌려져 있을 때 좋아요 데이터 삭제
if(isLiked === true) {
Axios.post('/api/like/delLike', variables)
.then(res => {
if(res.data.success) {
//좋아요 여부를 false로, 좋아요 갯수를 1 감소.
setIsLiked(false)
setNumLike(numLike - 1)
} else {
console.log(res.data)
}
})
}
}
//싫어요 누르기
const onClickDislike = () => {
//비디오와 코멘트의 싫어요 데이터 나누기
let variables = {}
if(props.videoId) {
variables = { userId, videoId: props.videoId }
} else if(props.commentId) {
variables = { userId, commentId: props.commentId }
}
//싫어요가 안눌려져 있을 때 싫어요 데이터 등록
if(isDisliked === false) {
Axios.post('/api/like/regDislike', variables)
.then(res => {
if(res.data.success) {
//좋아요 여부를 true로, 좋아요 갯수를 1 추가.
setIsDisliked(true)
setNumDislike(numDislike + 1)
if(isLiked === true) {
setIsLiked(false)
setNumLike(numLike - 1)
}
} else {
console.log(res.data)
}
})
}
//싫어요가 눌려져 있을 때 싫어요 데이터 삭제
if(isDisliked === true) {
Axios.post('/api/like/delDislike', variables)
.then(res => {
if(res.data.success) {
//좋아요 여부를 false로, 좋아요 갯수를 1 감소.
setIsDisliked(false)
setNumDislike(numDislike - 1)
} else {
console.log(res.data)
}
})
}
}
server/routes/like.js
import { Like } from '../../models/Like'
import { Dislike } from '../../models/Dislike'
//좋아요 데이터 등록
router.post('/regLike', (req, res) => {
//비디오와 코멘트의 좋아요 데이터 나누기
let variables = {}
if(req.body.videoId) {
variables = { userId: req.body.userId, videoId: req.body.videoId }
} else if(req.body.commentId) {
variables = { userId: req.body.userId, commentId: req.body.commentId }
}
//좋아요 데이터 저장
const like = new Like(variables)
like
.save(err => {
if(err) return res.status(400).json({ success: false, err })
//싫어요 데이터가 있다면 삭제함.
Dislike
.findByIdAndDelete(variables)
.exec(err => {
if(err) return res.status(400).json({ success: false, err })
res.status(200).json({ success: true })
})
})
})
//좋아요 데이터 삭제
router.post('/delLike', (req, res) => {
//비디오와 코멘트의 좋아요 데이터 나누기
let variables = {}
if(req.body.videoId) {
variables = { userId: req.body.userId, videoId: req.body.videoId }
} else if(req.body.commentId) {
variables = { userId: req.body.userId, commentId: req.body.commentId }
}
//좋아요 데이터 삭제
Dislike
.findByIdAndDelete(variables)
.exec((err, dislike) => {
if(err) return res.status(400).json({ success: false, err })
res.status(200).json({ success: true })
})
})
//싫어요 데이터 등록
router.post('/regDislike', (req, res) => {
//비디오와 코멘트의 싫어요 데이터 나누기
let variables = {}
if(req.body.videoId) {
variables = { userId: req.body.userId, videoId: req.body.videoId }
} else if(req.body.commentId) {
variables = { userId: req.body.userId, commentId: req.body.commentId }
}
//싫어요 데이터 저장
const dislike = new Dislike(variables)
dislike
.save(err => {
if(err) return res.status(400).json({ success: false, err })
//좋아요 데이터가 있다면 삭제함.
Like
.findByIdAndDelete(variables)
.exec(err => {
if(err) return res.status(400).json({ success: false, err })
res.status(200).json({ success: true })
})
})
})
//싫어요 데이터 삭제
router.post('/delDislike', (req, res) => {
//비디오와 코멘트의 좋아요 데이터 나누기
let variables = {}
if(req.body.videoId) {
variables = { userId: req.body.userId, videoId: req.body.videoId }
} else if(req.body.commentId) {
variables = { userId: req.body.userId, commentId: req.body.commentId }
}
//싫어요 데이터 삭제
Dislike
.findByIdAndDelete(variables)
.exec((err, dislike) => {
if(err) return res.status(400).json({ success: false, err })
res.status(200).json({ success: true })
})
})
찜하기 기능을 찜하기 버튼이 눌려져 있을 때와 아닐 때를 나눠서 구현한다.
- 찜하기 버튼이 안 눌려져 있을 때 찜하기 버튼 클릭 => 해당 데이터 찜하기 등록
- 찜하기 버튼이 눌려져 있을 때 찜하기 버튼 클릭 => 해당 데이터 찜하기 삭제
찜하기 기능 데이터를 DB에 저장하기 위해 Favorite모델을 생성한다.
server/models/favorite.js
import mongoose from 'mongoose'
const Schema = mongoose.Schema
const favoriteSchema = mongoose.Schema({
userId: {
type: Schema.types.ObjectId,
ref: 'User'
},
movieId: {
type: Schema.types.ObjectId,
ref: 'Movie'
}
}, { timeStamp: true })
const Favorite = mongoose.model('favorite', favoriteSchema)
module.exports = { Favorite }
- DB에 해당 무비의 찜하기 갯수가 몇개인지에 대한 데이터 가져오기.
- 찜하기를 이미 내가 눌렀는지에 대한 데이터 가져오기.
client
//해당 데이터를 State에 저장한다.
import React, { useEffect, useState } from 'react'
import { Axios } from 'axios'
import { useParams } from 'react-router-dom'
const [numFavorite, setNumFavorite] = useState(0)
const [isFavorite, setIsFavorite] = useState(null)
useEffect(() => {
const userId = localStorage.getItem({ "userId" })
const { movieId } = useParamas()
const variables = { userId, movieId }
//해당 무비의 찜하기 갯수 데이터 가져와 state에 저장한다.
Axios.post('/api/favorite/numFavorite', variables)
.then(res => {
if(res.data.success) {
setNumFavorite(res.data.numFavorite)
} else {
console.log(res.data)
}
})
//해당 무비를 내가 이미 찜하기 했는지에 대한 데이터를 가져와 state에 저장한다.
Axios.post('/api/favorite/isFavorite', variables)
.then(res => {
if(res.data.success) {
setIsFavorite(res.data.isFavorite)
} else {
console.log(res.data)
}
})
}, [])
app.js에서 routes해준다.
server/app.js
app.use('/api/favorite', require('./routes/favorite'))
server/routes/favorite.js
import express from 'express'
const router = express.Router()
//해당 무비의 찜하기 갯수를 보내줌.
router.post('/numFavorite', (req, res) => {
Favorite
.find({ "movieId": req.body.movieId })
.exec((err, favorites) => {
if(err) return res.status(400).json({ success: false, err })
res.status(200).json({ success: true, numFavorite: favorites.length })
})
})
//해당 무비의 찜 여부를 보내줌.
router.post('/isFavorite', (req, res) => {
Favorite
//userId와 movieId를 동시에 가지고 있는 document의 여부
.find({ "userId": req.body.userId, "movieId": req.body.movieId })
.exec((err, favorite) => {
if(err) return res.status(400).json({ success: false, err })
let isFavorite = false
if(favorite.length !== 0) {
isFavorite = true
res.status(200).json({ success: true, isFavorite })
} else {
res.status(200).json({ success: true, isFavorite })
}
})
})
- 찜하기 버튼이 안 눌려져 있을 때 찜하기 버튼 클릭 => 해당 데이터 찜하기 등록
- 찜하기 버튼이 눌려져 있을 때 찜하기 버튼 클릭 => 해당 데이터 찜하기 삭제
client
const [numFavorite, setNumFavorite] = useState(0)
const [isFavorite, setIsFavorite] = useState(null)
const onClickFavorite = () => {
const userId = localStorage.getItem({ userId })
const { movieId } = useParmas()
const variables = { userId, movieId }
//찜하기 버튼이 안눌려져 있을 때 => 찜하기 등록
if(!isFavorite) {
Axios.post('/api/favorite/regFavorite', variables)
.then(res => {
if(res.data.success) {
setIsFavorite(true)
setNumFavorite(numFavorite + 1)
} else {
console.log(res.data)
}
})
//찜하기 버튼이 눌려져 있을 때 => 찜하기 삭제
} else {
Axios.post('/api/favorite/delFavorite', variables)
.then(res => {
setIsFavorite(false)
setNumFavorite(numFavorite - 1)
})
}
}
server/routes/favorite.js
//Favorite컬렉션에 해당 DB document등록
router.post('/regFavorite', (req, res) => {
const favorite = new Favorite(req.body)
fovorite
.save(err => {
if(err) return res.status(400).json({ success: false, err })
})
})
//Favorite컬렉션에 해당 DB document삭제
router.post('/delFavorite', (req, res) => {
Favorite
.findOneAndDelete({
"userId": req.body.userId, "movieId": req.body.movieId
})
.exec(err => {
if(err) return res.status(400).json({ success: false, err })
})
})
내(userId)가 찜한 무비 데이터를 가져와서 상태 값(state)에 넣어준다.
client
const [favoriteData, setFavoriteData] = useState([])
useEffect(() => {
const userId = localStorage.getItem('userId')
const variable = { userId }
Axios.post('/api/favorite/getFavorite', variable)
.then(res => {
if(res.data.success) {
setFavoriteData(res.data.favoriteData)
} else {
console.log(res.data)
}
})
}, [])
server/routes/favorite.js
//populate("movieId")로 해당 userId document 필드에 저장된 movieId의 Movie document를 불러온다.
router.post('/getFavorite', (req, res) => {
Favorite
.find({ "userId": req.body.userId })
.populate("movieId")
.exec((err, favoriteData) => {
if(err) return res.status(400).json({ success: false, err })
res.status(200).json({ success: true, favoriteData })
})
})