state 끌어올리기

YunKuk Park·2021년 12월 19일
0

👣 하나씩 꾸준히

목록 보기
10/15

동일한 데이터에 대한 변경사항을 여러 컴포넌트에 반영해야 할 필요가 있다.
이럴 때에는 가장 가까운 공통 조상으로 state를 끌어올리는게 좋다. -React 공식문서-

state끌어올리기는 그럼 왜 하는가? => 동기화!!

Props vs State

props : 고정값(기본값으로 사용), READ ONLY
state : 가변값, 사용자가 이벤트 요청시 변경 (수정 가능)

  1. props는 스마트폰의 볼륨버튼이라면 사용자가 볼륨버튼을 누르면
    state는 스마트폰안에서 스스로의 상태인 볼륨이 바뀌게 해놓은 모든 조치라고 할 수 있다.
  2. 상위 Component하위 Component에게 props를 통해 값을 전달하여 내부의 state를 바꾸기 때문에 컴포넌트 스스로 외부에서 전달되는 props를 변경하는 것은 금지되어 있다.
    또한, 하위 컴포넌트가 상위 컴포넌트를 동작시키려면 props를 전달하는게 아니라, 상위 컴포넌트 안에 이벤트를 심고 거기서 useState로 만들어진 setState를 통해 값을 변경 해야 한다.

댓글 등록 구현

const Feed = props => {
  const { userName, userAvatar, feedImg, content, likeHit, comments } = props;
  const [feedComments, setFeedComments] = useState(comments);
  const commentLenght = feedComments.length;

  const addNewComment = newComment => {  // 자식에게 전달해줄 함수
    setFeedComments([...feedComments, newComment]);
  };

  const deleteComment = comment => {   // 자식에게 전달해줄 함수
    const copyFeedComments = [...feedComments];
    const comments = copyFeedComments.filter(
      feedComment => feedComment.id !== comment.id
    );
    setFeedComments(comments);
  };

  return (
    ...
    <div className="feed-wrapper">
      <section className="feed-bottom">
        <div className="feed-bottom-info">
          <FeedDesc
            userName={userName}
            content={content}
            comments={feedComments}
            onDeleteButtonClick={deleteComment}  // deleteComment 함수를 props로 전달
          />
        </div>
      </section>
      <CommentInput
        onButtonClick={addNewComment}  // addNewComment 함수를 props로 전달 
        commentLenght={commentLenght}
      />
    </div>
  );
};

export default Feed;
import React, { useRef, useState } from 'react';

const CommentInput = props => {
  const { onButtonClick, commentLenght } = props; // 부모에게 받아온 Click이벤트 변수에 저장
  const [newCommentContent, setNewCommentContent] = useState('');

  const onClickSubmit = () => {
    const newComment = {
      id: commentLenght + 1,
      userName: 'hello._.',
      content: newCommentContent,
    };

    onButtonClick(newComment);  // submit이 될 때 부모에게서 받아온 onButtonClick에 새로운 코멘트를 넣어 전달해준다. 
    inputRef.current.value = '';
  };

  return (
    <section className="comment-wrapper">
      <button type="button">
        <i className="far fa-smile" />
      </button>
      <input
        name="comment"
        type="text"
        placeholder="댓글 달기..."
        onChange={e => onTextChange(e)}
        onKeyDown={e => {
          if (e.code === 'Enter') onClickSubmit();
        }}
        ref={inputRef}
      />
      <button
        className="comment-submit-button button-primary"
        disabled={buttonSwitch}
        onClick={onClickSubmit}
      >
        게시
      </button>
    </section>
  );
};

export default CommentInput;
  1. 부모에게 addNewComment 함수 선언 (commentState에 새로 받아온 comment를 추가하는 함수)
const addNewComment = newComment => {  // 자식에게 전달해줄 함수
    setFeedComments([...feedComments, newComment]);
  };
  1. 자식에게 props로 전달
<CommentInput
  onButtonClick={addNewComment}  // addNewComment 함수를 props로 전달 
  commentLenght={commentLenght}
/>
  1. props로 받아온 값 자식에서 사용
  const onClickSubmit = () => {
    const newComment = {
      id: commentLenght + 1,
      userName: 'hello._.',
      content: newCommentContent,
    };

    onButtonClick(newComment);  // submit이 될 때 부모에게서 받아온 onButtonClick에 새로운 코멘트를 넣어 전달해준다. 
    inputRef.current.value = '';
  };
  1. onButtonClick(newComment) 가 실행되면서 부모에 있던 addNewComment 함수가 실행!
  2. addNewComment 에서 setFeedComments([...feedComments], newComment) 를 통해 comment state 다시 셋팅

댓글 삭제 구현

  1. deleteComment 함수 선언
  const deleteComment = comment => {
    const copyFeedComments = [...feedComments];
    const comments = copyFeedComments.filter( 
      feedComment => feedComment.id !== comment.id
    );
    setFeedComments(comments);
  };
  1. <Feed />에서 <FeedDesc />에게 onDeleteButtonClick = {deleteComment} 로 함수 전달
  2. <FeedDesc />에서 <CommentList /> 에게 또 함수 전달
<ul className="feed-comment-list">
  {comments.map(comment => (
    <CommentList
      key={comment.id}
      comment={comment}
      onDeleteButtonClick={onDeleteButtonClick}
    />
  ))}
</ul>
  1. <CommentList /> 에서 삭제할 comment onDeleteButtonClick함수 에게 전달하며 실행
<button
  type="button"
  onClick={() => {
    // delete target comment
    onDeleteButtonClick(comment);
  }}
>
  1. onDeleteButtonClick(comment)가 실행되며 코멘트 삭제
  const deleteComment = comment => {
    const copyFeedComments = [...feedComments];
    const comments = copyFeedComments.filter( 
      // 내가 선택한 id가 아닌 것들만 comments 에 다시 집어 넣어주기
      feedComment => feedComment.id !== comment.id
    );
    setFeedComments(comments);
  };
profile
( • .̮ •)◞⸒⸒

0개의 댓글