React_Mission 3. map함수 활용한 댓글 기능 구현

ha ju·2021년 5월 4일
0
post-thumbnail

⭐ React_Mission 3. map함수 활용한 댓글 기능 구현

1. state 정의

  constructor() {
    super();
    this.state = {
      commentValue: '',
      commentList: [],
    };
  }
  • 우선, 부모 컴포넌트의 state에는 우리가 작성하고 있는 댓글값을 가져올 commentValue라는 key키와 댓글 submit시, 해당 글을 담아주는 배열인 commentList라는 key를 지정해주었다.
  • commentList라는 배열을 만들어준 이유는 map이라는 배열 매서드를 사용하여 댓글을 업로드시켜줄것이기 때문이다.

👇

2. 작성중인 댓글을 state에 저장

  handleCommentInput = e => {
    this.setState({
      commentValue: e.target.value,  //이벤트가 실행되는 타겟 요소의 벨류값을 저장
    });
  };
  • Mission 1 로그인창의 input에서 했던 것처럼 input 입력값을 state에 저장해준다.
    1)<Textarea>에 onChange이벤트 설정 (onChange={this.handleCommentInput})
    2) handleCommentInput 함수로 input 입력값을 state에 저장

👇

3. 버튼 클릭 이벤트와 함수 생성

  addComment = () => {
    const { commentList, commentValue } = this.state; //구조 분해 할당
    this.setState({
      commentList: commentList.concat([commentValue]),
      commentValue: '',
    });
  • 버튼 클릭하면 this.state의commentList에 value값 담기
    1) 게시 버튼에는 onClick이벤트 (onClick={this.addComment})
    2) 이벤트 발생 시 실행되는 함수 생성
- 게시' 버튼이 눌리는 순간에 this.state에 발생하는 것
1. `commentList` 라는 배열에 `commentValue`로 담아줬던 값들을 담아주는 동시에,
2. `commentValue` 값은 다시 아무것도 없게된다.
	- (concat() :빈 배열에 입력한 값을 담은 배열을 붙인 결과가 된다.)
	- javascript push()메서드와 비슷한 역할

javascript에서 보통 배열에 데이터를 추가할 때에는 push()메서드를 써주었기 때문에 이 방법으로 생각하고 있었는데 
react에서는 state 내부의 값을 직접적으로 수정하면 절대로 안된다고한다.(불면성 유지)
하여, push, splice, unshift, pop 같은 내장함수는 배열 자체를 직접 수정하게 되므로 적합하지 않아 
대신에 존의 배열에 기반하여 새 배열을 만들어내는 함수인 concat, slice, map, filter 같은 함수를 사용해야한다고 한다.
* push : 기존 배열 자체를 변경
* concat : 새로운 배열을 만들어줌

3-1. 엔터 쳤을 때도 똑같이 작동하도록

  addCommEnter = e => {
    if (e.key === 'Enter') {
      this.addComment();
    }
  };
  • textarea에 onKeyPress 이벤트걸어주기 (onKeyPress={this.addCommEnter})
  • 게시 버튼(<button>)에 이벤트걸어주는 것이 아니라는 것을 확실히 하고 넘어가자
  • 이벤트에 해당하는 key값이 Enter이면 addComment 함수를 실행하도록(this.addComment())

🍒 3-2. <testarea> -> <input> & <form>태그에 onSubmit이벤트

  <form className="feeds_upload_wright" onSubmit={this.addComment}>
     {/* <i className="far fa-smile icon"></i> */}
       <FontAwesomeIcon icon={faSmile} className="far fa-smile icon" />
        <input
          placeholder="댓글 달기..."
          onChange={this.handleCommentInput}
          ></input>
       <button type="submit">게시</button>
 </form>
  • 인스타그램 클론 할 때 많은 분들이 댓글입력창을 <textarea>가 아닌 <input>으로 넣어주셨고 button에는 type속성을 submit으로 주고 감싸진 form 태그에 onSubmit이벤트를 걸어주는 쪽으로 많이 하셨다.
  • 이렇게 하면 엔터 쳤을 때의 이벤트를 따로 걸어주지 않아도 돼서 나도 아래처럼 코드를 수정해주었고, 필요 없는addCommEnter함수는 삭제해주었다

👇

4. ⭐배열, map() 을 활용하여 댓글 업로드시키기

   <form className="feeds_upload_comments">
      <li>
        <span className="comment_writer">yyeon_jju</span>
        <span className="comment_content">너무 예뻐요~~</span>
      </li>
        {this.state.commentList.map((commentElement, idx) => {        //⭐map() 메서드 활용⭐
           return <li key={idx}>{commentElement}</li>;
            })}
   </form>
  • 3번에서는 commentList라는 state에 배열 형태로 댓글의 value 값들을 담아주었다.
  • 우리는 이제 댓글 창에 배열에 담긴 각각의 요소들을 <li>화 시켜서 return한 값을 렌더링시켜줘야한다.
  • 배열의 요소들을 각각<li>태그 안에 담아서 리턴시켜줘야 하기 때문에 요소들에 각각 접근하여 새로운 값으로 반환시키는 map()메서드를 활용하였다.
  • 우리가 주의를 기울여야할 코드는 아래 두 줄 이다.
    - 우선 state에서 commentList에 접근해서 해당 배열을 사용해야 하기 때문에
    - this.state.commentList.map((commentElement, idx) 이렇게 배열에 접근하여 배열의 요소들을 인자로 주었다.
    - return할 값은 우리가 반환하고 싶은 태그와 넘겨받은 파라미터를 사용하여 표현해주었다.
    {this.state.commentList.map((commentElement, idx) => {    
      return <li key={idx}>{commentElement}</li>;
       })}

👇

⭐ input 입력값 초기화

위의 단계까지 실행하고 댓글을 submit하면,댓글 창에 잘 올라오긴하는데 input에 작성해준 값이 초기화되지 않고 계속 그대로 유지가 될 것이다. 해결하려면 어떻게 해야할까?

  • 🍒 우리는 input의 value값을 submit할 때 두가지 작업을 하고 싶다
    1) 3번addComment 함수와 4번에서 작성해준 것 같이 input value값이 댓글 창에 올라가도록
    2) input value값이 초기화되도록
  • 위의 이 기능은 각각 따로 실행되어야한다.
    이를 위해 나는 input의 value라는 attribute를 통해서 input의 value값의 상태를 바꿔주기로했다

1) 🍒 input를 입력하면 입력값을 담고, 댓글 업로드 후에는 비워주기 위해 this.state에 value : ''라는 초기값을 넣어주었다.(input의 초기 상태는 빈 문자열이기 때문이다)

  constructor() {
    super();
    this.state = {
      commentValue: '',
      commentList: [],
      value: '',
    };
  }

2) 🍒 input태그 내에 value라는 attribute에 this.state의 value라는 키값을 적용해주었다.

 <input
   placeholder="댓글 달기..."
   onChange={this.handleCommentInput}
   value={this.state.value} 
    ></input>

3) 🍒 input의 onChange 이벤트 실행 시 handleCommentInput에서 this.state.commentValue 뿐만아니라 this.state.value도 함께 값을 넣어주어야 한다.

 handleCommentInput = e => {
    this.setState({
      commentValue: e.target.value,  //⭐두 개의 state에 모두 입력값을 저장해주어야한다⭐
      value: e.target.value,      //⭐두 개의 state에 모두 입력값을 저장해주어야한다⭐
    });
  };

4) 🍒 input입력값이 submit되는 순간 (1)입력값이 댓글창에 업로드되는 작업 & (2)화면에 보이는 value값이 초기화는 작업이 필요한다. (1)번은 3번에서 마무리되었었고 (2)번 작업은 간단하다.

  • addComment 함수에 this.state에서 정의해준 value값을 다시 빈 문자열로 만들어주는 작업을 추가해주면된다.
  • 이렇게 하면 input태그에 들어있던 value attribue도 this.state.value를 참조하면서 입력값이 초기화된다.
  addComment = e => {
    e.preventDefault();
    const { commentList, commentValue } = this.state;
    this.setState({
      commentList: commentList.concat([commentValue]),
      commentValue: '',
      value: '',      //⭐this.state.value를 다시 빈 문자열로⭐
    });
  };

0개의 댓글