[Westagram] 리액트로 댓글 기능 구현

OROSY·2021년 8월 21일
2

React

목록 보기
13/27
post-custom-banner

🍀 React.js

이번 3주차부터 파운데이션 기간이 시작되었습니다. 프론트엔드는 React.js에 대해 본격적으로 배우고 백엔드는 django를 심화하여 실제로 회원가입, 로그인 등의 기능을 구현하는 것이 과제로 나가게 되었죠.

사실 저는 이전에 위코드를 등록할 때, 예리님이 조언해주신 것처럼 자바스크립트에 시간을 몰두하였습니다. 그래서 자바스크립트와 매우 친해졌고, HTML, CSS보다 편하게 코딩을 진행할 수 있었습니다.

다만, 문제는 리액트였습니다. 리액트는 패스트캠퍼스 강의로 잠깐 들으면서 강의 내용만 블로그로 정리했다뿐이지 실제로 코드는 1도 이해하지 못하면서 치는 것이 사실이었습니다. 그러나 이번 파운데이션 기간에는 리액트와 친해지자라는 목표로 개인적으로 독학도 하고, 좋은 멘토분들이 해주시는 세션에 집중해서 학습을 했습니다.

이번 주를 통해서 리액트와 절친이다까지는 절대 아니지만, 이제는 얼굴은 아는 사이정도 까지는 발전한 것 같습니다. 그래서 이번 글은 제가 이전에는 바닐라 자바스크립트로 댓글 작성을 구현한 코드를 리액트로 변경한 것을 보여드리려 합니다.

이번에는 휘찬님 블로그에 도움을 받아서 문제를 해결할 수 있었습니다. 라이브러리 없는 순수한 리액트로 댓글을 작성하는 방법에 대해 알아봅시다.

📚 Mission 3) Main | 댓글 기능

  1. 사용자가 댓글 입력 후 enter 를 누르거나 오른쪽의 버튼 클릭 시 댓글이 추가되도록 구현해주세요.
  2. 댓글 기능을 구현하기 위해서는 배열 데이터 타입을 활용해야 합니다.
  3. Array.map 참고해서 시도해주세요.

🏳️‍🌈 분할 정복

  1. 먼저, 미션의 첫 번째 상황부터 보겠습니다. 사용자가 엔터를 누르거나 오른쪽 '게시'버튼 클릭 시 댓글이 추가되도록 구현해야합니다. 저는 이를 해결하기 위해서 input, button 태그를 form 태그로 감쌌습니다. 그렇게 되면, 두 가지 상황에서 댓글이 작성될 수 있기 때문입니다.
  2. 결국 댓글 기능을 구현하기 위해서는 배열 데이터 타입을 활용해야합니다. 사용자가 쓰는 댓글이 배열 데이터로 들어와야하고, 이를 위해서는 state의 값을 [] 배열로 주어져야 한다는 뜻으로 해석했습니다.
  3. 댓글을 하나하나씩 댓글창에 나타내기 위해서는 위에서 주어진 Array.map이라는 배열 메소드를 사용해야 합니다. 아시다시피 해당 메소드는 배열의 데이터를 각각 돌면서 주어진 조건에 따라 값을 변화시키고 그 값을 리턴해줍니다.
    이 부분에서는 리액트에서 배우는 Key와 List라는 개념이 중요하기 때문에 공식 문서를 읽어보시는 것을 권해드립니다. 저도 아직 이해가 많이 부족해서 여러 번 읽어보고 있는 중입니다.

🎬 구현 화면

💻 댓글 기능 코드

일단, 저의 구현한 코드를 보시기 전에 휘찬님 블로그에서 배우는 기초적인 댓글 작성 기능 구현에 대해 알아보겠습니다. 이후 제 코드는 간단하게만 보여드리는 것으로 마무리하겠습니다.

class Comment extends Component {
  super();
  this.state = {
    value= "",
  }

  render() {
    return (
      <div>
        <input type="text" />
        <button>submit</button>
        <ul>
          <li>hello</li>
        </ul> 
      </div>
    );
  }
}	

먼저, 간단하게 클래스로 state에 value 값을 초기화해주었습니다. 그리고 아래에는 댓글을 입력할 인풋과 글을 게시하는 버튼이 있습니다.

그렇다면, 이제 인풋에 입력하는 값을 가져오는 함수를 정의해야합니다. 그러기 위해 먼저 인풋에 이벤트를 입력해보도록 하죠.

<input onChange={this.getValue} type="text" />

이제 위와 같이 인풋의 값이 변화함에 따라 값을 가져오는 이벤트를 입력했습니다. 이제 함수를 정의해봅시다.

class Comment extends Component {
  super();
  this.state = {
    value= "",
    commentList = [],
  }

  this.getValue = (e) => {
    this.setState(
      value: e.target.value
    )
  }
  
  render() {
    return (
      <div>
        <form onSubmit={this.addComment}>
          <input onChange={this.getValue} type="text" />
          <button>게시</button>
          <ul>
            <li>hello</li>
          </ul>
        </form>
      </div>
    );
  }
}	

위와 같이 state에 commentList라는 변수를 배열 데이터로 지정해줬습니다. 그래야 버튼을 클릭하며, 들어오는 데이터들이 배열로 자연스레 들어갈 수 있을테니까요.

그리고 아까 정의한 this.getValue라는 함수를 정의했습니다. 함수 내에서는 반드시 this.setState를 사용해야한다는 사실! 알고 계시겠죠? 이를 이용해 e.target.value로 사용자에게 입력받는 값을 변수 value에 넣어줍니다.

이후에 form에 onSubmit 이벤트로 addComment라는 함수가 실행될 수 있도록 코드를 작성했습니다. 그렇다면, 당연히 이제 addComment를 정의하러 가볼까요.

class Comment extends Component {
  super();
  this.state = {
    value= "",
    commentList = [],
  }
  
// 사용자로 부터 받아오는 값을 value에 업데이트 
  this.getValue = (e) => {
    this.setState({
      value: e.target.value
    })
  }
  
// 사용자로부터 받아오는 값을 commentList에 배열 데이터 추가 & 댓글 초기화
  this.addComment = () => {
    this.setState({
      commentList: this.state.commentList.concat([this.state.value)]),
      value= "",
    })
  }
   
  render() {
    return (
      <div>
        <form onSumbit={this.addComment}>
          <input onChange={this.getValue} type="text" />
          <button>게시</button>
          // 댓글 입력 공간
          <ul>
            <li>hello</li>
          </ul>
        </form>
      </div>
    );
  }
}	

주석으로 달아놓은 각각의 함수를 보시면 어떤 역할을 하고 있는지 이해하실 수 있을 겁니다. 이제 거의 다 왔습니다! 마지막으로 commentList로 받아온 배열을 화면에 그려야 할 것입니다. 여기서 위에서 언급한 Array.map이 등장합니다. 그리고 위에 댓글 입력 공간이라고 쓰인 곳에 아래 코드가 입력되는 것입니다.

<ul>
  <li>hello</li>
    {this.state.commentList.map((comment, index) => {
      <li>{comment}</li>
  })}
</ul>

이제 여기서 중요한 Key와 List 개념이 등장합니다. 위와 같이, 코드를 작성해도 무리 없이 댓글이 작성이 되실 겁니다. 다만, 콘솔창을 열어보면 아래와 같은 오류가 발생합니다. (추가적으로, map의 경우 오류가 발생해도 실행이 되는 건 자동으로 키 값이 인덱스 번호로 주어지기 때문입니다.)

여기서 key 값은 각각의 배열 안의 데이터들은 유니크한 값들이 와야합니다. map 메소드 내에서 주어지는 index라는 것을 사용해도 좋지만, 현재 Key와 List 공식 문서에서는 이것보다는 더욱 고유한 값이 오는 것을 추천한다고 합니다.

하지만, 이 상황에서는 다른 방법이 없기에 아래와 같이 key에 index를 적용하여 코드를 작성합니다.

<ul>
  <li>hello</li>
    {this.state.commentList.map((comment, index) => {
      <li key={index}>{comment}</li>
  })}
</ul>

🧑‍💻 실제 구현 코드


저는 별도로 위와 같이 댓글을 작성해서 화면에 구현하는 것만 EachComment라는 컴포넌트를 만들어서 부모 컴포넌트인 Comment에 넣어주었습니다.

다만, 여기서 다음 미션이 댓글 하나하나씩을 컴포넌트화하는 작업인데 이 부분을 진행중인데 쉽지가 않네요.. 오늘 안으로 파란별님과 힘을 모아서 해결해보고 될 때까지 잠을 안자보려 하는데 어떻게 될지는 모르겠습니다.

그리고 위 댓글 기능 구현 사항에 대해서 혹시 덧붙이실 말이 있으시다면 언제든 환영이니 댓글 부탁드려요. 감사합니다😁

profile
Life is a matter of a direction not a speed.
post-custom-banner

0개의 댓글