메인페이지에서 컴포넌트 구성은 다음과 같다.
Feeds는 모든 피드에 대한 데이터를 가지고 있다.
한 피드에 관련된 데이터를 각각 Feed컴포넌트에 전달해준다.
return (
<div className="feeds">
{feeds && feeds.map(feed => <Feed key={uuid()} feed={feed} />)}
<div className="feed-end" ref={feedEndRef}>
feedEnd
</div>
</div>
);
댓글 추가 삭제 기능을 구현할 함수를 정의해준다.
const [comments, setComments] = useState(commentData);
function deleteComment(comment) {
const updated = comments;
const filtered = updated.filter(com => {
return com.id !== comment.id;
});
setComments(filtered);
}
function addComment(e) {
e.preventDefault();
let updated = comments;
const newCommentVal = commentRef.current.value;
updated = [
...updated,
{ id: uuid(), commentId: myId, commentText: newCommentVal },
];
setComments(updated);
commentRef.current.value = '';
}
<form class="comment-input">
<input
type="text"
placeholder=" 댓글 달기..."
class="text"
ref={commentRef}
/>
<button onClick={addComment}>게시</button>
</form>
댓글 입력창과 버튼은 피드 컴포넌트 안에 있으므로 하위컴포넌트에 함수를 전달하지 않고 해당 컴포넌트에서 처리한다.
댓글 버튼에 addComment()함수를 등록한다.
Feed컴포넌트에서 Comments로 댓글 데이터를 전달한다.
<Comments comments={comments} deleteComment={deleteComment} />
Comments는 한 피드에 달린 댓글들을 전달받았다.
Comment 컴포넌트에 각각 하나의 댓글들을 전달해준다. 이때 똑같이 deleteComment()도 전달한다.
import React from 'react';
import Comment from '../Comment/Comment';
import { v4 as uuid } from 'uuid';
function Comments({ comments, deleteComment }) {
const commentList = comments;
return (
<ul class="comments">
{commentList.map(com => (
<Comment key={uuid()} comment={com} deleteComment={deleteComment} />
))}
</ul>
);
}
export default Comments;
Comment에서 각각의 댓글들에 달린 삭제 버튼을 클릭하면 onDelete()가 호출된다.
이 onDelete()함수는 deleteComment(Comment)를 호출하는데,
여기서 state 끌어올리기가 발생한다.
import React from 'react';
import { TiDelete } from 'react-icons/ti';
function Comment({ comment, deleteComment }) {
const onDelete = () => {
deleteComment(comment);
};
return (
<li class="comment-container">
<span class="comment">
<p class="id">{comment.commentId}</p>
<span>{comment.commentText}</span>
</span>
<button class="delete" onClick={onDelete}>
<TiDelete size="15" />
</button>
</li>
);
}
export default Comment;
리액트의 데이터 흐름은 상위 컴포넌트에서 하위 컴포넌트로 전달하는 하향식이자 단방향 데이터 흐름을 따른다.
state 끌어올리기는 반대로 데이터를 끌어올리는 것인데, 공유될 상태를 소유한 컴포넌트가 진리의 원천(source of truth)가 되며, 하위 컴포넌트에서 이 상위 컴포넌트의 상태를 갱신하는 것이다.
이 state 끌어올리기를 활용하는 방법은 어렵지 않다.
상위 컴포넌트에 정의된 상태를 변경하는 함수 자체를 하위 컴포넌트에 props로 전달하고, 하위 컴포넌트에서 이 콜백함수를 호출하면 된다.
단방향 데이터 흐름의 원칙을 지키면서 하위 컴포넌트로 전달되어 호출되면 상위 컴포넌트의 상태에 영향을 미치는데, 이것을 state 끌어올리기라고 한다.
이 프로젝트에서도 state 끌어올리기를 사용했는데,
각각의 댓글 컴포넌트에서 삭제 버튼을 누르면 상위의 피드 데이터를 변경해야 했다.
이를 위해 deleteComment()는 comment를 인자로 받고,전달받은 comment를 Feed컴포넌트에 있는 comments state에 setComments를 사용해 업데이트 한다.