티스토리 뷰

728x90
반응형

1. SingleComment.js 생성

아래의 이미지처럼 해당하는 위치에 SingleComment.js파일을 생성한다.

SingleComment.js 생성하기

 

2. Single Comment를 위한 Template 생성

만든 파일에 아래와 같은 템플릿을 작성한다.

// client > src > components > views > VideoDetailPage > Sections > SingleComment.js
import React from "react";
import { Comment, Avatar, Button, Input } from "antd";

const { TextArea } = Input;

function SingleComment() {
  return (
    <div>
      <Comment action author avatar={<Avatar src alt />} content />
      <form style={{ display: "flex" }} onSubmit>
        <textarea
          style={{ width: "100%", borderRadius: "5px" }}
          placeholder="코멘트를 작성해주세요."
          onChange
          value
        />
        <br />
        <button style={{ width: "20%", height: "52px" }} onClick>
          Submit
        </button>
      </form>
    </div>
  );
}

export default SingleComment;

이렇게 만든 경우 아래와 같은 하단에 이미지로 바뀔 것이다.

SingleComment.js 템플릿 완성 후 화면

 

3. Open Reply func와 handleChange func 만들기

3-1. Open Reply func

두 개의 form을 하나는 reply to를 클릭하였을 때만 보여주는 함수를 만들려 한다.

// client > src > components > views > VideoDetailPage > Sections > SingleComments.js

import React, { useState } from "react";
import { Comment, Avatar, Button, Input } from "antd";

const { TextArea } = Input;

function SingleComment() {
  const [OpenReply, setOpenReply] = useState(false);

  const onClickReplyOpen = () => {
    setOpenReply(!OpenReply);
  };
  const actions = [
    <span onClick={onClickReplyOpen} key="comment-basic-reply-to">
      Reply to
    </span>,
  ];
  return (
    <div>
      <Comment actions={actions} author avatar={<Avatar src alt />} />
      {OpenReply && (
        <form style={{ display: "flex" }}>
          <textarea
            style={{ width: "100%", borderRadius: "5px" }}
            placeholder="코멘트를 작성해주세요."
          />
          <br />
          <button style={{ width: "20%", height: "52px" }}>Submit</button>
        </form>
      )}
    </div>
  );
}

export default SingleComment;

useState를 사용하여 코멘트를 사라지고 보이게 할 수 있게 해 준다. OpenReply를 이용하여 토글 기능을 활용(!OpenReplay : 토글로 On/Off 기능을 사용)하여 On이 되었을 때, form값을 실행하도록 코딩을 하였다.

 

3-2. handleChange func

다음으로는 코멘트를 쓰고 value값을 넣는 함수를 만들어보도록 하겠다.

// client > src > components > views > VideoDetailPage > Sections > SingleComments.js

import React, { useState } from "react";
import { Comment, Avatar, Button, Input } from "antd";

const { TextArea } = Input;

function SingleComment() {
  // 중략
  const [CommentValue, setCommentValue] = useState();
  
  const onHandleChange = (e) => {
    setCommentValue(e.currentTarget.CommentValue);
  };
  // 중략
  return (
    <div>
      <!-- 중략 -->
          <textarea
            style={{ width: "100%", borderRadius: "5px" }}
            placeholder="코멘트를 작성해주세요."
            value={CommentValue}
            onChange={onHandleChange}
          />
          <!-- 중략 -->
        </form>
      )}
    </div>
  );
}

export default SingleComment;

<textarea> 태그에는 덧글을 달 내용을 입력하는 곳으로 value는 useState를 사용하여 값이 실시간으로 들어가게 해준다. 그리고 onChange함수를 사용하여 변화하는 값을 CommentValue값에 똑같은 내용으로 전달되게 진행한다.

 

4. OnSubmit func 만들기

먼저 submit 함수를 만든다.

// client > src > components > views > VideoDetailPage > Sections > SingleComments.js

import React, { useState } from "react";
import { Comment, Avatar, Button, Input } from "antd";

const { TextArea } = Input;

function SingleComment() {
  // 중략
  
  const onHandleChange = (e) => {
    setCommentValue(e.currentTarget.CommentValue);
  };
  const onSubmitCommnet = (e) => {
    e.preventDefault();

    const variables = {
      content: CommentValue,
      writer: user.userData._id,
      postId: props.postId,
      responseTo: props.comment._id,
    };
    Axios.post("/api/comment/saveComment", variables).then((response) => {
      if (response.data.success) {
        console.log(response.data.result);
        props.refreshFunction(response.data.result);
        setcommentValue("");
      } else {
        alert("덧글 저장하지 못하였습니다.");
      }
    });
  };
  
  // 중략
  return (
    <div>
      <Comment
        actions={actions}
        author={props.comment.writer.name}
        avatar={<Avatar src={props.comment.writer.image} />}
        content={<p>{props.comment.content}</p>}
      />
      {OpenReply && (
        <form style={{ display: "flex" }} onSubmit={onSubmitCommnet}>
          <textarea
            style={{ width: "100%", borderRadius: "5px" }}
            placeholder="코멘트를 작성해주세요."
            value={CommentValue}
            onChange={onHandleChange}
          />
          <br />
          <button
            style={{ width: "20%", height: "52px" }}
            onClick={onSubmitCommnet}
          >
            Submit
          </button>
        </form>
      )}
    </div>
  );
}

export default SingleComment;

ㄹform값에서 onSubmit함수를 만든 후 해당하는 함수의 설정을 진행한다.

 

postId

여기서 responseTo값은 부모 컴포넌트 Comment.js에 SingleComment 태그안에서 postId값으로 상속받게 한다. 이미 Comment.js 또한 부모 컴포넌트에서 받아온 것이므로 간단하게 코드만 추가하면 된다.

// client > scr > components > views > VideoDetailPage > Sections > Comment.js

// 중략

      {/* Comment Lists */}
      <SingleComment postId={props.postId} />
      // 중략

 

5. 모든 Comment 정보들을 데이터베이스에서 가져오기

가장 부모가 되는 VideoDetailPage.js에서 데이터베이스를 가져와야 하는데 먼저 API를 생성한다. 이전에 댓글을 달았던 내용들을 모두 가져오기 위해서는 다음과 같은 코드를 작성해야 한다.

// server > routes > comments.js

// 중략

router.post("/getComment", (req, res) => {
  Comment.find({ postId: req.body.videoId })
    .populate("writer")
    .exec((err, comments) => {
      if (err) return res.status(400).send(err);
      res.status(200).json({ success: true, comments });
    });
});

module.exports = router;

postId에 맞는 모든 comments의 정보를 가져온다.

 

그런 다음 VideoDetailPage.js에 다음과 같은 코드를 추가한다.

// client > src > components > views > VideoDetailPage > VideoDetailPage.js

// 중략

  const [Comments, setComments] = useState([]);

  useEffect(() => {
    Axios.post("/api/video/getVideoDetail", videoVariable).then((response) => {
		// 중략
    });

    Axios.post("/api/comment/getComments", videoVariable).then((response) => {
      if (response.data.success) {
        setComments(response.data.Comments);
        console.log(response.data.Comments);
      } else {
        alert("덧글에 대한 정보를 가져오는 것에 실패를 하였습니다.");
      }
    });
  }, []);
  
  return (
   {/* 중략 */}
                <Comment
              commentLists={Comments}
              postId={videoId}
            />
            {/* 중략 */}
  );
  
  // 중략

Comments에 모든 정보를 State에 배열로 가져오도록 하였다. 그리고 Comment에 prop으로 postId값을 넣어준다. 그러면 하위 컴포넌트에는 prop를 이용한 commentLists를 이용하여 Comments 이름으로 저장을 하여 받을 수 있다.

 

commentLists를 map함수를 이용하여 덧글을 배열형식으로 가져올 수 있게 한다.

// client > scr > components > views > VideoDetailPage > Sections > Comment.js

// 중략

      {/* Comment Lists */}
      {props.commentLists &&
        props.commentLists.map(
          (comment, index) =>
            !comment.responseTo && (
              <SingleComment
                comment={comment}
                postId={props.postId}
              />
            )
        )}
      // 중략

 

 

그리고 다시 하위컴포넌트에 comment값을 props를 해준다.

// client > src > components > views > VideoDetailPage > Sections > SingleComments.js

import React, { useState } from "react";
import { Comment, Avatar, Button, Input } from "antd";

const { TextArea } = Input;

function SingleComment() {
  // 중략
  const [CommentValue, setCommentValue] = useState();
  
  const onHandleChange = (e) => {
    setCommentValue(e.currentTarget.CommentValue);
  };
  
  // 중략
  
  return (
    <div>
      <Comment
        actions={actions}
        author={props.comment.writer.name}
        avatar={<Avatar src={props.comment.writer.image} />}
        content={<p>{props.comment.content}</p>}
      />
      
      {/* 중략 */}
    <div>
);

export default SingleComment;

content값과 avatar, author 등을 가져올 수 있다.

 

6. 저장된 댓글을 Parent Component에다가 업데이트

SingleComment와 Comment 모두가 VideoDetailPage에 comment값을 저장을 하게 되는데, 업데이트가 될 경우 자동적으로 자식 컴포넌트에도 뿌려주는 기능에 대한 코드를 작성하는 방법이다.

// client > src > components > views > VideoDetailPage > VideoDetailPage.js

// 중략

  const [Comments, setComments] = useState([]);

  useEffect(() => {
    Axios.post("/api/video/getVideoDetail", videoVariable).then((response) => {
		// 중략
    });

    Axios.post("/api/comment/getComments", videoVariable).then((response) => {
      // 중략
  }, []);
  
  const refreshFunction = (newComment) => {
    setComments(Comments.concat(newComment));
  };
  
  return (
   {/* 중략 */}
            <Comment
              refreshFunction={refreshFunction}
              commentLists={Comments}
              postId={videoId}
            />
            {/* 중략 */}
  );
  
  // 중략

refreshFunction으로 함수를 생성한 후 Comment 컴포넌트 안에 prop을 이용하기 위해서 refreshFunction값을 넣어준다.

 

 

 

728x90
반응형
댓글
250x250
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함