과제로 주어진 댓글 기능에 필요한 요건은 다음과 같았다.
- 사용자가 댓글 입력 후 enter를 누르거나 '게시' 버튼을 클릭 했을 때 댓글이 추가되도록 구현
- 생성 되는 댓글마다 컴포넌트화 시킬 것
우선 댓글이 게시되도록 해보자.
댓글이 게시되기 위한 프로세스는 다음과 같다.
리액트 환경에서 기능을 구현하기 위해서는 상하위 컴포넌트 간에 이동을 해야하는 경우가 생기므로, 기능 구현 과정의 역순으로 생각해보자.
- 실제로 브라우저에 댓글을 생성하는 함수 정의
⬇- 컴포넌트화 된 댓글들이 변화시킬 state에 대한 정의
⬇- 생성될 개별적 댓글의 컴포넌트화 과정을 정의
⬇- 브라우저에 랜더링 될 댓글의 형태를 컴포넌트로 정의
⬇- 특정한 조건에 의해 활성화 될 버튼에 prop을 부여
⬇- 버튼을 활성화시키도록 부여될 prop의 조건에 대한 정의
1. 실제로 브라우저에 댓글을 생성하는 함수 정의
2. 컴포넌트화 된 댓글들이 변화시킬 state에 대한 정의
const onSubmit = event => {
event.preventDefault();
if (comment === '') {
return;
}
setCommentArray([...commentArray, comment]);
setComment('');
};
지금 이 시점에서 알 수 없는 변수명이 네개가 있다.
함수를 정의하는 과정에서 차후에 필요하게 될 것이기 때문에 차후에 정의한 변수들이다. 함수를 작동시키기 위해 변해야 하는 state들을 정의한다.
const [comment, setComment] = useState('');
const [commentArray, setCommentArray] = useState([]);
comment는 문자열 데이터이고, setComment함수로 state가 변화하게 된다.
commentArray는 배열형 데이터이고, setCommentArray함수로 state가 변화하게 된다.
comment, commentArray가 props로써 활용되는 방법은 아래의 과정을 거치면서 알 수 있다.
comment와 commentArray는 (차후에 밝혀질테지만) comment는 최상위 컴포넌트에서 <input>
태그의 value속성에 대한 속성값으로 state가 변하게 되고, 추가될 댓글의 형태를 정의할 컴포넌트에서 <p>
에 들어갈 입력값, 즉 댓글 본문이 comment의 state가 된다고 정의된다.
그러므로 그 점에 착안하여 해석하자면 '만약 댓글 본문이 빈 문자열이면' 아무런 조치없이 함수를 빠져나오고, 그렇지 않다면 setCommentArray라는 배열의 마지막 배열로 변화된 state의 comment를 포함시키고, 현재 댓글 <input>
의 입력값을 비우라는 의미가 된다.
3. 생성될 개별적 댓글의 컴포넌트화 과정을 정의
<div class="commentPlus">
{commentArray.map((commentItem, index) => (
<NewComment comment={commentItem} key={index} />
))}
</div>
"commentPlus"라는 빈 배열에 "commentArray"라는 배열이 들어가고 map이라는 메소드에 따라서 각각의 배열 원소에 대해서 for 반복문을 작동시키듯이 깊은 복사를 하고, 각각에 index값을 부여하게 된다.
*이부분은 map 메소드를 공부하면서 다시 한번 확인해보자.
4. 브라우저에 랜더링 될 댓글의 형태를 컴포넌트로 정의
const NewComment = ({ comment }) => {
return (
<div className="replyUserDiv">
<div className="userComment">
<strong>allong_sio</strong>
<p className="onSubmitComment">{comment}</p>
</div>
<div className="likeDelete">
<img className="likeBtn" src="images/jaehongChoi/heart.png" alt="" />
</div>
</div>
);
};
사전에 바닐라JS로 만들면서 불필요한 <div>
태그들을 많이 만들었고, 이것을 react환경에 복붙하면서 그대로 유지하고 있는 모습이다. 너무 많은 css 속성들이 부여되었기 때문에 불가피하게 구조를 유지하여 진행하였다.
'NewComment'라는 컴포넌트는 {comment}라는 prop 인자를 받아 상기와 같은 구조로 랜더링 되게 된다.
5. 특정한 조건에 의해 활성화 될 버튼에 prop을 부여
6. 버튼을 활성화시키도록 부여될 prop의 조건에 대한 정의
앞의 로그인 프로세스에서도 똑같은 과정을 다뤘지만 다시 한번 복기해보자.
변화를 감지할 <input>
태그에 "onChange" prop 부여, "onChange" prop에 대한 속성값으로 "handleCommentInput" 컴포넌트 함수 부여.
const handleCommentInput = event => {
setComment(event.target.value);
if (!!event.target.value) {
setIsActive(true);
} else {
setIsActive(false);
}
};
isActive의 state가 변함에 따라서 <button>
태그의 "disabled" prop 활성화
#질문1)
onChange = {handleCommentInput}
이 아니라onChange = {handleCommentInput()}
는 왜 안 될까?
답: 로그인에서도 다뤘지만 "onChange"의 속성값으로 함수를 받는다. 함수에 대한 결과값이 아니라.