[(과제) [React] State, Props, Event] - 3

장운서·2021년 6월 28일
0

react

목록 보기
4/9
post-thumbnail

Mission 3) Main | 댓글 기능

  • 사용자가 댓글 입력 후 enter 를 누르거나 왼쪽의 버튼 클릭 시 댓글이 추가되도록 구현해주세요.
  • 댓글 기능을 구현하기 위해서는 배열 데이터 타입을 활용해야 합니다.
  • Array.map 참고해서 시도해주세요.
  • 위 순서대로 완료 후 Add : Mission 3 - 댓글 기능 구현 commit message를 남긴 후 push 해주세요.

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 값들을 담아주었다.
우리는 이제 댓글 창에 배열에 담긴 각각의 요소들을

  • 화 시켜서 return한 값을 렌더링시켜줘야한다.
    배열의 요소들을 각각
  • 태그 안에 담아서 리턴시켜줘야 하기 때문에 요소들에 각각 접근하여 새로운 값으로 반환시키는 map()메서드를 활용하였다.

    • 우리가 주의를 기울여야할 코드는 아래 두 줄 이다.<
      - 우선 state에서 commentList에 접근해서 해당 배열을 사용해야 하기 때문에
      - this.state.commentList.map((commentElement, idx) 이렇게 배열에 접근하여 배열의 요소들을 인자로 주었다.
      - return할 값은 우리가 반환하고 싶은 태그와 넘겨받은 파라미터를 사용하여 표현해주었다.
        {this.state.commentList.map((commentElement, idx) => {    
          return <li key={idx}>{commentElement}</li>;
           })}
     위의 단계까지 실행하고 댓글을 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를 다시 빈 문자열로⭐
        });
      };
    profile
    방향성을 찾고싶은 프론트엔드개발자

    0개의 댓글