React

 

 

 

John Ahn

 

인프런   ==>     라하며 배우는 노드, 리액트 시리즈 - 유튜브 사이트 만들기

 

 

유튜브 강의 목록 :   https://www.youtube.com/playlist?list=PL9a7QRYt5fqnlSRu--re7N_1Ean5jFsh3

 

강의 파일 : https://cdn.jsdelivr.net/gh/braverokmc79/react-youtube-clone@v1.0.0/Youtube%20Clone%20(Ko).pdf

 

Boiler Plate  소스 https://github.com/braverokmc79/ReactYoutubeCloneSeries

완성본 소스 (John Ahn:  https://github.com/jaewonhimnae/react-youtube-clone

소스 https://github.com/braverokmc79/react-youtube-clone

 

 

강의 목록

1.유튜브 사이트 만들기
2.전체적인 틀 만들고 MongoDB 연결
3.비디오 업로드 FORM 만들기1
4.비디오 업로드 FORM 만들기2
5.Multer로 노드 서버에 비디오 저장하기
6. ffmpeg로 비디오 썸네일 생성하기
7.비디오 업로드 하기
8.랜딩 페이지에 비디오들 나타나게 하기
9.비디오 디테일 페이지 만들기
10.디테일 비디오 페이지에 Side 비디오 생성
11.구독 기능 1
12.구독 기능 2
13.구독 비디오 페이지
14.댓글 기능 생성 1 구조 설명
15.댓글 기능 생성 2 Comment js
16.댓글 기능 생성 3 SingleComment
17.댓글 기능 생성 4 ReplyComment
18.좋아요 싫어요 기능1 구조 설명
19.좋아요 싫어요 기능2 템플릿, 데이터 가져오기
20.좋아요 싫어요 기능 3 클릭시 기능들
 

 

 

 

 

18.좋아요 싫어요 기능1 구조 설명

 

 

 

 

Node.js

 

models/Like.js

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


const likeSchema = 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 }

 

 

/models/Dislike.js

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


const dislikeSchema = 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 }

 

 

 

 

 

 

 

 

 

 

 

 

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

 

 

 

 

 

 

1) Node.js

routes/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;

 

 

 

2) 리액트

1.VideoDetailPage/VideoDetailPage.js

 

~~

~

~

       <List.Item
                            actions={[<LikeDislikes video userId={localStorage.getItem("userId")} videoId={videoId} />, subscribeButton]}
                        >
                            <List.Item.Meta
                                avatar={<Avatar src={VideoDetail.writer && VideoDetail.writer.image} />}
                                title={VideoDetail.writer.name}
                                description={VideoDetail.description}
                            />
                        </List.Item>



~
~

 

 

 

 

2.VideoDetailPage/Sections/SingleComment.js

 

~

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

~~

 

 

 

 

3.VideoDetailPage/Sections/LikeDislikes.js

/* eslint-disable array-callback-return */
import React, { useEffect } from 'react'
import { Tooltip, Icon } from 'antd';
import Axios from 'axios';
import { useState } from 'react';



function LikeDislikes(props) {

    const [Likes, setLikes] = useState(0);
    const [Dislikes, setDislikes] = useState(0);
    const [LikeAction, setLikeAction] = useState(null);
    const [DislikeAction, setDislikeAction] = useState(null);


    let variable = "";
    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(res => {
                if (res.data.success) {

                    //얼마나 많은 좋아요를 받았는지
                    setLikes(res.data.likes.length)

                    //내가 이미 그 좋아요를 눌렀는지
                    res.data.likes.map(like => {
                        if (like.useId === props.userId) {
                            setLikeAction('liked');
                        }
                    });

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

            });

        Axios.post("/api/like/getDisLikes", variable)
            .then(res => {
                if (res.data.success) {

                    //얼마나 많은 싫어요를 받았는지
                    setDislikes(res.data.dislikes.length);

                    //내가 이미 싫어요를 눌렀는지
                    res.data.dislikes.map(dislike => {
                        if (dislike.useId === props.userId) {
                            setDislikeAction('disliked');
                        }
                    });

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

            });

    }, [])


    return (
        <div>
            <span className="comment-basic-like">
                <Tooltip title="Like">
                    <Icon type="like" theme={LikeAction === "liked" ? 'filled' : 'outlined'} />
                </Tooltip>
                <span style={{ padding: 8, cursor: "auto" }}>{Likes}</span>
            </span>

            <span className="comment-basic-like">
                <Tooltip title="DisLike">
                    <Icon type="dislike" theme={DislikeAction === "disliked" ? 'filled' : 'outlined'} />
                </Tooltip>
                <span style={{ padding: 8, cursor: "auto" }}>{Dislikes}</span>
            </span>

        </div >
    )
}

export default LikeDislikes

 

 

 

 

 

 

 

 

 

20.좋아요 싫어요 기능 3 클릭시 기능들

 

 

 

 

 

 

1) Node.js

routes/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 })
        })
});


//좋아요 증가처리
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 }
    }

    const like = new Like(variable)

    //1.Like collection 에다가 클릭 정보를 넣는다.
    like.save((err, likeResult) => {
        if (err) return res.json({ success: false, err });

        //2. 만약에 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 })
        })

});



//싫어요 감소 처리
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 }
    }

    const dislike = new Dislike(variable)

    //1.Dislike collection 에다가 클릭 정보를 넣는다.
    dislike.save((err, dislikeResult) => {
        if (err) return res.json({ success: false, err });

        //2. 만약에 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 })
            })

    })

});




module.exports = router;

 

 

 

 

2) 리액트

1.VideoDetailPage/Sections/LikeDislikes.js

/* eslint-disable array-callback-return */
import React, { useEffect } from 'react'
import { Tooltip, Icon } from 'antd';
import Axios from 'axios';
import { useState } from 'react';



function LikeDislikes(props) {

    const [Likes, setLikes] = useState(0);
    const [Dislikes, setDislikes] = useState(0);
    const [LikeAction, setLikeAction] = useState(null);
    const [DislikeAction, setDislikeAction] = useState(null);


    let variable = "";
    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(res => {
                if (res.data.success) {

                    //얼마나 많은 좋아요를 받았는지
                    setLikes(res.data.likes.length)

                    //내가 이미 그 좋아요를 눌렀는지
                    res.data.likes.map(like => {
                        console.log("내가 이미 그 좋아요를 눌렀는지 : ", like.userId);
                        if (like.userId === props.userId) {
                            setLikeAction('liked');
                        }
                    });

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

            });

        Axios.post("/api/like/getDisLikes", variable)
            .then(res => {
                if (res.data.success) {
                    //얼마나 많은 싫어요를 받았는지
                    setDislikes(res.data.dislikes.length);

                    //내가 이미 싫어요를 눌렀는지
                    res.data.dislikes.map(dislike => {
                        if (dislike.userId === props.userId) {
                            setDislikeAction('disliked');
                        }
                    });
                } else {
                    alert("DisLikes 에 정보를 가져오지 못했습니다.");
                }

            });

    }, [])







    const onLike = () => {
        //console.log(" variable : ", variable);

        if (LikeAction === null) {
            Axios.post('/api/like/upLike', variable)
                .then(res => {
                    if (res.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(res => {
                    if (res.data.success) {
                        setLikes(Likes - 1);
                        setLikeAction(null);
                    } else {
                        alert("Like를 내리지 못하였습니다.");
                    }
                })

        }
    }

    const onDislike = () => {

        if (DislikeAction !== null) {
            Axios.post("/api/like/unDislike", variable)
                .then(res => {
                    if (res.data.success) {
                        setDislikes(Dislikes - 1);
                        setDislikeAction(null);
                    } else {
                        alert("dislike 를 지우지 못하였습니다.");
                    }

                })

        } else {
            Axios.post("/api/like/upDislike", variable)
                .then(res => {
                    if (res.data.success) {
                        setDislikes(Dislikes + 1);
                        setDislikeAction("disliked");

                        if (LikeAction !== null) {
                            setLikeAction(null);
                            setLikes(Likes - 1);
                        }
                    } else {
                        alert("DisLike 를 올리지 못하였습니다.")
                    }
                })

        }
    }

    return (
        <div>
            <span className="comment-basic-like" >
                <Tooltip title="Like">
                    <Icon type="like" theme={LikeAction === "liked" ? 'filled' : 'outlined'} onClick={onLike} />
                </Tooltip>
                <span style={{ padding: 8, cursor: "auto" }}>{Likes}</span>
            </span>&nbsp;&nbsp;

            <span className="comment-basic-like">
                <Tooltip title="DisLike">
                    <Icon type="dislike" theme={DislikeAction === "disliked" ? 'filled' : 'outlined'} onClick={onDislike} />
                </Tooltip>
                <span style={{ padding: 8, cursor: "auto" }}>{Dislikes}</span>
            </span>&nbsp;&nbsp;

        </div>
    )
}

export default LikeDislikes

 

 

2.src/components/views/VideoDetailPage/Sections/SingleComment.js

 

~

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



~

 

 

 

 

 

 

 

 

 

 

react

 

about author

PHRASE

Level 60  라이트

One of these days is none of these days. (차일 피일 미루면 영원히 못한다.)

댓글 ( 4)

댓글 남기기

작성