클론코딩

[인프런] 유튜브 사이트 만들기 (3)

cmkoi1 2023. 1. 22. 15:26

따라하며 배우는 노드, 리액트 시리즈 - 유튜브 사이트 만들기 강의

 

[무료] 따라하며 배우는 노드, 리액트 시리즈  - 유튜브 사이트 만들기 - 인프런 | 강의

이 강의를 통해 리액트와 노드의 개념을 익히는 것뿐만이 아닌 실질적으로 어떻게 웹사이트를 만들 수 있는지를 배울 수 있습니다., - 강의 소개 | 인프런...

www.inflearn.com

※ 해당 링크 강의 내용을 바탕으로 작성된 포스팅입니다.

 

 

 

좋아요 싫어요 기능 생성 (1) 구조 설명

1. Like & DisLike Model 만들기

각 모델에 들어가야 하는 값. Dislike임.

  • boilerplate-mern-stack-master\server\models 경로에 Like.js 파일과 Dislike.js 파일 생성.

Like.js

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const likeSchema = mongoose.Schema({
    userId: {
        type: Schema.Types.ObjectId,
        ref: 'User'
    },
    commentId: {
        type: Schema.Types.ObjectId, 
        ref: 'Comment'
    },
    videoId: {
        type: Schema.Types.ObjectId, 
        ref: 'Video'
    }

}, { timestamps: true }) //만든날과 업데이트날 표시


const Like = mongoose.model('Like', likeSchema);

module.exports = { Like }


Dislike.js

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const dislikeSchema = mongoose.Schema({
    userId: {
        type: Schema.Types.ObjectId,
        ref: 'User'
    },
    commentId: {
        type: Schema.Types.ObjectId, 
        ref: 'Comment'
    },
    videoId: {
        type: Schema.Types.ObjectId, 
        ref: 'Video'
    }

}, { timestamps: true }) //만든날과 업데이트날 표시


const Dislike = mongoose.model('Dislike', dislikeSchema);

module.exports = { Dislike }

 

2. 구조 설명

Like 버튼 구조 설명
Dislike 버튼 구조 설명

 

 

 

좋아요 싫어요 기능 (2) 템플릿, 데이터 가져오기

1. AntD을 이용하여 Like & Dislike 버튼 만들기


VideoDetailPage.js

import LikeDislikes from './Sections/LikeDislikes';
                        <List.Item
                            actions={[ <LikeDislikes />, subcribeButton ]}
                        >

 

  • boilerplate-mern-stack-master\client\src\components\views\VideoDetailPage\Sections 경로에 LikeDislikes.js 파일 생성.

LikeDislikes.js

import React from 'react'
import { Tooltip, Icon } from 'antd';

function LikeDislikes() {
    return (
        <div>
            <span key="comment-basic-like">
                <Tooltip title="Like">
                    <Icon type="like"
                        theme="filled"
                        onClick
                    />
                </Tooltip>
                <span style={{ paddingLeft:'8px', cursor:'auto' }}> 1 </span>
            </span>

            <span key="comment-basic-dislike">
                <Tooltip title="Dislike">
                    <Icon type="dislike"
                        theme="outlined"
                        onClick
                    />
                </Tooltip>
                <span style={{ paddingLeft:'8px', cursor:'auto' }}> 1 </span>
            </span>
        </div>
    )
}

export default LikeDislikes

 

2. DB에서 현재 좋아요 싫어요에 대한 정보 가져오기

  • 좋아요 싫어요 정보가 비디오에 대한 것인지, 댓글에 대한 것인지 나눠 줘야 한다. 따라서, Request 보낼 때 변수는 Video와 Comment가 달라야 한다.

VideoDetailPage.js

                        <List.Item
                            actions={[ <LikeDislikes video userId={localStorage.getItem('userId')} videoId={videoId} />, subcribeButton ]}
                        >


SingleComment.js

import LikeDislikes from './LikeDislikes';
    const actions = [
        <LikeDislikes userId={localStorage.getItem('userId')} commentId={props.comment._id} />,
        <span onClick={onClickReplyOpen} key="comment-basic-reply-to">Reply to</span>
    ]


LikeDislikes.js

import Axios from 'axios';
function LikeDislikes(props) {

    let variable = { } //비디오에 대한 거면 videoId, 댓글에 대한 거면 commentId

    if(props.video) {
        variable = { videoId: props.videoId, userId: props.userId  }
    } else {
        variable = { commentId: props.commentId, userId: props.userId }
    }

    useEffect(() => {
        Axios.post('/api/like/getLikes', variable )
            .then(response => {
                if(response.data.success) {

                } else {
                    alert('Likes에 대한 정보를 가져오지 못했습니다.')
                }
            })
        Axios.post('/api/like/getDislikes', variable )
            .then(response => {
                if(response.data.success) {

                } else {
                    alert('DisLikes에 대한 정보를 가져오지 못했습니다.')
                }
            })
    }, [])

 

  • boilerplate-mern-stack-master\server\routes 경로에 like.js 파일 생성 및 comment.js 파일 내용 복사 후 수정.

like.js

const express = require('express');
const router = express.Router();

const { Like } = require("../models/Like");
const { Dislike } = require("../models/Dislike");

//=================================
//             Like
//=================================

router.post("/getLikes", (req, res) => {

    let variable = {}

    if(req.body.videoId) {
        variable = { videoId: req.body.videoId }
    } else {
        variable = { commentId: req.body.commentId }
    }

    Like.find(variable)
        .exec((err, likes) => {
            if(err) return res.status(400).send(err)
            res.status(200).json({ success: true, likes })
        })

});

router.post("/getDislikes", (req, res) => {

    let variable = {}

    if(req.body.videoId) {
        variable = { videoId: req.body.videoId }
    } else {
        variable = { commentId: req.body.commentId }
    }

    Dislike.find(variable)
        .exec((err, dislikes) => {
            if(err) return res.status(400).send(err)
            res.status(200).json({ success: true, dislikes })
        })

});

module.exports = router;


index.js

app.use('/api/like', require('./routes/like'));

 

2-1. 좋아요 싫어요 수와 좋아요나 싫어요 둘 중 하나 클릭 여부


LikeDislikes.js

function LikeDislikes(props) {

    const [Likes, setLikes] = useState(0)
    const [Dislikes, setDislikes] = useState(0)
    const [LikeAction, setLikeAction] = useState(null)
    const [DisLikeAction, setDisLikeAction] = useState(null)
    useEffect(() => {
        Axios.post('/api/like/getLikes', variable )
            .then(response => {
                if(response.data.success) {

                    // 받은 좋아요 수
                    setLikes(response.data.likes.length)

                    // 내가 누른 좋아요 유무
                    response.data.likes.map(like => {
                        if(like.userId === props.userId) { //비디오나 코멘트의 모든 like와 내가 누른 like가 같으면
                            setLikeAction('liked')
                        }
                    })

                } else {
                    alert('Likes에 대한 정보를 가져오지 못했습니다.')
                }
            })

        Axios.post('/api/like/getDislikes', variable )
            .then(response => {
                if(response.data.success) {

                    // 받은 싫어요 수
                    setDislikes(response.data.dislikes.length)

                    // 내가 누른 싫어요 유무
                    response.data.dislikes.map(dislike => {
                        if(dislike.userId === props.userId) { //비디오나 코멘트의 모든 dislike와 내가 누른 dislike가 같으면
                            setDisLikeAction('disliked')
                        }
                    })

                } else {
                    alert('DisLikes에 대한 정보를 가져오지 못했습니다.')
                }
            })

    }, [])

 

2.2 기타 수정 사항


LikeDislikes.js

                    <Icon type="like"
                        theme={LikeAction === 'liked'? 'filled' : 'outlined'}
                        onClick
                    />
                <span style={{ paddingLeft:'8px', cursor:'auto' }}> {Likes} </span>
                    <Icon type="dislike"
                        theme={DisLikeAction === 'disliked'? 'filled' : 'outlined'}
                        onClick
                    />
                <span style={{ paddingLeft:'8px', cursor:'auto' }}> {Dislikes} </span>

 

 

 

좋아요 싫어요 기능 (3) 클릭시 기능들

1. onLike func 만들기


LikeDislikes.js

    const onLike = () => {

        if(LikeAction === null) { //좋아요 클릭 안 되어있을 때

            Axios.post('/api/like/upLike', variable)
                .then(response => {
                    if(response.data.success) {

                        setLikes(Likes +1)
                        setLikeAction('liked')

                        if(DisLikeAction !== null ) { //싫어요가 클릭되어 있었을경우
                            setDisLikeAction(null)
                            setDislikes(Dislikes -1)
                        }

                    } else {
                        alert('Like를 올리지 못했습니다.')
                    }
                })
        } else { //좋아요가 클릭 되어 있을 때

            Axios.post('/api/like/unLike', variable)
                .then(response => {
                    if(response.data.success) {
                        setLikes(Likes -1)
                        setLikeAction(null)
                    } else {
                        alert('Like를 내리지 못했습니다.')
                    }
                })

        }

    }
                    <Icon type="like"
                        theme={LikeAction === 'liked'? 'filled' : 'outlined'}
                        onClick={onLike}
                    />


like.js

router.post("/upLike", (req, res) => {

    let variable = {}

    if(req.body.videoId) { //비디오 혹은 코멘트 아이디와 유저 아이디가 매칭되어야 함
        variable = { videoId: req.body.videoId, userId: req.body.userId }
    } else {
        variable = { commentId: req.body.commentId, userId: req.body.userId }
    }

    //Like collection에다가 클릭 정보 넣기
    const like = new Like(variable)

    like.save((err, likeResult) => {
        if(err) return resjson({ success: false, err })

        //Dislike가 이미 클릭되었을 때, Dislike 1 줄이기
        Dislike.findOneAndDelete(variable)
            .exec((err, disLikeResult) => {
                if(err) return res.status(400).json({ success: false, err })
                res.status(200).json({ success: true })
            })

    })

});

router.post("/unLike", (req, res) => {

    let variable = {}

    if(req.body.videoId) {
        variable = { videoId: req.body.videoId, userId: req.body.userId }
    } else {
        variable = { commentId: req.body.commentId, userId: req.body.userId }
    }

    Like.findOneAndDelete(variable)
        .exec((err, result) => {
            if(err) return res.status(400).json({ success: false, err })
            res.status(200).json({ success: true })
        })

});

 

2. onDisLike func 만들기


LikeDislikes.js

    const onDisLike = () => {

        if(DisLikeAction !== null) {
            
            Axios.post('/api/like/unDislike', variable)
                .then(response => {
                    if(response.data.success) {
                        setDislikes(Dislikes -1)
                        setDisLikeAction(null)
                    } else {
                        alert('dislike를 지우지 못했습니다.')
                    }
                })

        } else {
            
            Axios.post('/api/like/upDislike', variable)
                .then(response => {
                    if(response.data.success) {
                        setDislikes(Dislikes +1)
                        setDisLikeAction('disliked')

                        if(LikeAction !== null) {
                            setLikeAction(null)
                            setLikes(Likes -1)
                        }
                    } else {
                        alert('dislike를 지우지 못했습니다.')
                    }
                })

        }

    }
                    <Icon type="dislike"
                        theme={DisLikeAction === 'disliked'? 'filled' : 'outlined'}
                        onClick={onDisLike}
                    />


like.js

router.post("/unDislike", (req, res) => {

    let variable = {}

    if(req.body.videoId) {
        variable = { videoId: req.body.videoId, userId: req.body.userId }
    } else {
        variable = { commentId: req.body.commentId, userId: req.body.userId }
    }

    Dislike.findOneAndDelete(variable)
        .exec((err, result) => {
            if(err) return res.status(400).json({ success: false, err })
            res.status(200).json({ success: true })
        })

});

router.post("/upDislike", (req, res) => {

    let variable = {}

    if(req.body.videoId) {
        variable = { videoId: req.body.videoId, userId: req.body.userId }
    } else {
        variable = { commentId: req.body.commentId, userId: req.body.userId }
    }

    //Dislike collection에다가 클릭 정보 넣기
    const dislike = new Dislike(variable)

    dislike.save((err, likeResult) => {
        if(err) return resjson({ success: false, err })

        //Like가 이미 클릭되었을 때, Like 1 줄이기
        Like.findOneAndDelete(variable)
            .exec((err, likeResult) => {
                if(err) return res.status(400).json({ success: false, err })
                res.status(200).json({ success: true })
            })

    })

});

 

완성쓰

수정해야 하는 것

  • 비회원 댓글 작성 오류
  • 새로고침 시 3 Depth 댓글 사라지는 오류
728x90