(React) 4. 복습 번외편 : Comment 기능 -4-

김동우·2021년 8월 1일
0

wecode

목록 보기
25/32
post-thumbnail

잠깐! 시작하기 전에

이 글은 wecode에서 실제 공부하고(이제 사전 스터디는 아닙니다.), 이해한 내용들을 적는 글입니다. 글의 표현과는 달리 어쩌면 실무와는 전혀 상관이 없는 글일 수 있습니다.

또한 해당 글은 다양한 자료들과 작성자 지식이 합성된 글입니다. 따라서 원문의 포스팅들이 틀린 정보이거나, 해당 개념에 대한 작성자의 이해가 부족할 수 있습니다.

설명하듯 적는게 습관이라 권위자 발톱만큼의 향기가 날 수 있으나, 엄연히 학생입니다. 따라서 하나의 참고자료로 활용하시길 바랍니다.

글의 내용과 다른 정보나 견해의 차이가 있을 수 있습니다.
이럴 때, 해당 부분을 언급하셔서 제가 더 공부할 수 있는 기회를 제공해주시면 감사할 것 같습니다.


구현

3. 댓글이 나타나는 컴포넌트

댓글 정보를 받아 댓글을 구현하는 컴포넌트가 필요합니다.

그럼 저는 여기서 고민을 할겁니다.

하드코딩을 할 것인가? 외부 정보를 활용할 것인가?

에 대한 고민이 되겠습니다.

하드코딩을 하는 컴포넌트의 경우 상당히 정적인, static한 컴포넌트입니다.

하지만 저는 외부 정보를 사용하는 동적인, dynamic한 컴포넌트를 구성할 준비가 되었습니다.

몰라도 1번, 댓글 정보의 구조에서 이미 실루엣을 그렸을거고,

2번 form 태그의 구현에서 90% 이상 감이 온 상태일겁니다.

입력을 받는다는건 어딘가에 저장이 될지도 모른다~ 라는 생각이 들거고, 저장이 된다면 불러오는게 가능하다는 결론까지 이어졌을겁니다.

그러나 제 local에는 DB가 없으니, 이걸 state로 구현해보는 방식을 선택할겁니다.

mock data와 fetch는 잠시 넣어두세요.

그럼 3번을 구현하기 전에, 2번에서 댓글 정보를 상위 컴포넌트에서 다루기로 했던 생각이 문득 스쳐지나갑니다.

상위 컴포넌트를 작성합시다.


import React from "react";
import CommentForm from "./commentForm";

class Main extends React.Component {
  render() {
    return (
      <div>
        <CommentForm />
      </div>
    );
  }
}

export default Main;

정말 간단한 컴포넌트가 완성됩니다.

그리고 댓글 정보를 다루고 있는 컴포넌트는 댓글을 그릴 수 있는 정보를 가지고 있게 됩니다.

import React from "react";
import CommentForm from "./commentForm";

class Main extends React.Component {
  constructor() {
    super();
    this.state = {
      comments: [],
    };
  }
  render() {
    const { comments } = this.state;
    return (
      <div>
        <CommentForm />
        {comments.map((elem) => {
          return (
            <div key={elem.id}>
              <span>{elem.user_name}</span>
              <span>{elem.commentText}</span>
              <span>{elem.like}</span>
            </div>
          );
        })}
      </div>
    );
  }
}

export default Main;

이런 구조로 무언가를 그려내겠네요.

문제는, 이 댓글 정보는 대부분 제출(게시)되는 순간 입력되는 정보입니다.

그럼 전 다시 form으로 돌아가서 약간의 코드행을 넣어줍니다.

import React from "react";
import CommentInput from "./commentInput";

class CommentForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      commentText: ``,
    };
  }

  setCommentText = (text) => {
    this.setState((prevState) => {
      return { ...prevState, commentText: text };
    });
  };

  handleSubmit = (event) => {
    event.preventDefault();
    const { commentText } = this.state;
    const { setCommentInfo, comments } = this.props;
    console.log(comments);

    let commentInfo = {
      id: comments.length !== 0 ? comments[comments.length - 1].id + 1 : 1,
      userName: "dongwu-Kim",
      commentText,
      liked: false,
      like: 26,
    };
    setCommentInfo(commentInfo);
    this.setState((prevState) => {
      return { ...prevState, commentText: `` };
    });
  };

  render() {
    const { handleSubmit, setCommentText } = this;
    const { commentText } = this.state;
    return (
      <form onSubmit={handleSubmit}>
        <CommentInput
          setCommentText={setCommentText}
          commentText={commentText}
        />
      </form>
    );
  }
}

export default CommentForm;

이런 정보를 구성할겁니다. DB가 없으니 userName, liked, like의 경우 직접 하드코딩 해야겠네요.

그럼, 이런 정보를 setCommentInfo 라는 props 메서드를 통해 Main에게 전달하는데, 코드는 다음과 같습니다.


import React from "react";
import CommentForm from "./commentForm";

class Main extends React.Component {
  constructor() {
    super();
    this.state = {
      comments: [],
    };
  }
  // state 끌어올리기 메서드
  setCommentInfo = (commentInfo) => {
    this.setState((prevState) => {
      return { ...prevState, comments: [...prevState.comments, commentInfo] };
    });
  };

  render() {
    const { setCommentInfo } = this;
    const { comments } = this.state;
    return (
      <div>
        <CommentForm setCommentInfo={setCommentInfo} comments={comments} />
        // 댓글 구현 
        {comments.map((elem) => {
          return (
            <div key={elem.id}>
              <span>{elem.userName}</span>
              <span>{elem.commentText}</span>
              <span>{elem.like}</span>
            </div>
          );
        })}
      </div>
    );
  }
}

export default Main;

그런데 댓글 구현이 참 볼품없으니 다시 컴포넌트로 바꿔보면,

//PaintComment
import React from "react";

class PaintComments extends React.Component {
  render() {
    const { comments } = this.props;
    return (
      <>
        {comments.map((elem) => {
          return (
            <div key={elem.id}>
              <span>{elem.userName}</span>
              <span>{elem.commentText}</span>
              <span>{elem.like}</span>
            </div>
          );
        })}
      </>
    );
  }
}

export default PaintComments;

//Main
import React from "react";
import CommentForm from "./commentForm";
import PaintComments from "./paintComments";

class Main extends React.Component {
  constructor() {
    super();
    this.state = {
      comments: [],
    };
  }
  setCommentInfo = (commentInfo) => {
    this.setState((prevState) => {
      return { ...prevState, comments: [...prevState.comments, commentInfo] };
    });
  };
  render() {
    const { setCommentInfo } = this;
    const { comments } = this.state;
    return (
      <div>
        <CommentForm setCommentInfo={setCommentInfo} comments={comments} />
        <PaintComments comments={comments} />
      </div>
    );
  }
}

export default Main;

위처럼 바꿀 수 있습니다.

결국 4번, 이벤트 컴포넌트와 댓글 컴포넌트의 위치까지 해결이 된 셈이네요.

댓글을 이런 방식으로 구현하는건 어디까지나 저의 방법입니다.

분명 다른 누군가는 더 훌륭하고 간단한 방법으로 구현하겠죠.

그럼에도 이렇게까지 나누어서 생각해보는 것은 큰 의미가 있었던 것 같습니다.

  1. 무엇보다도 내 기준이 뭔지 남에게 설명할 수 있다.

  2. 특정 기능에서 플로우 이해를 조금 더 해볼 수 있다.

이어서

여기서 더 나가서, 다음 글에서는 Like 구현도 해봅시다.

like 를 위해서는 button 태그와 event 처리를 조금 더 넣어줘야 합니다.

예시코드와 현재 파일의 코드는 무관할 것 같은데, 한 번 글을 쓰며 생각해보겠습니다.

1. intro
2. 댓글 정보 구조
3. 이벤트 컴포넌트
5. 좋아요 기능 추가

0개의 댓글