댓글 기능 (Comment - React) - feat CRUD
코멘트란?
다들 알고있는 댓글기능입니다.
CRUD연습하기 아주 좋은것같아 예제로 선택하였습니다.
우선 테스트케이스를 준비해봅시다.
comment.test.js
describe("show Test", () => {
const comment = [
{
id: 1,
userName: "zmf1111",
content: "1",
},
{
id: 2,
userName: "zmf1111",
content: "2",
},
{
id: 3,
userName: "zmf1111",
content: "3",
},
];
it("should add comment", () => {
const inputWord = "4";
const expected = [
{
id: 1,
userName: "zmf1111",
content: "1",
},
{
id: 2,
userName: "zmf1111",
content: "2",
},
{
id: 3,
userName: "zmf1111",
content: "3",
},
{
id: 4,
userName: "zmf1111",
content: "4",
},
];
expect(addComment(comment, inputWord)).toEqual(expected);
});
it("should remove select comment", () => {
const id = 2;
const expected = [
{
id: 1,
userName: "zmf1111",
content: "1",
},
{
id: 3,
userName: "zmf1111",
content: "3",
},
];
expect(removeComment(comment, id)).toEqual(expected);
});
it("should change content inputId comment", () => {
const id = 2;
const inputWord = "change";
const expected = [
{
id: 1,
userName: "zmf1111",
content: "1",
},
{
id: 2,
userName: "zmf1111",
content: "change",
},
{
id: 3,
userName: "zmf1111",
content: "3",
},
];
expect(chagneContent(comment, id, inputWord)).toEqual(expected);
});
const addComment = (comments, inputWord) => {
return comment.concat({
id: comments.length + 1,
content: inputWord,
userName: "zmf1111",
});
};
const removeComment = (comments, id) => {
return comments.filter((comment) => comment.id !== id);
};
const chagneContent = (comments, id, inputWord) => {
return comments.map((comment) => {
if (comment.id === id) {
return {
...comment,
content: inputWord,
};
}
return comment;
});
};
});
Comment.js
import React, { useContext, useState } from "react";
import styled from "styled-components";
import { UserContext } from "../datas/User/UserContextAPI";
const CommentWrapper = styled.div`
border: 1px solid black;
p{
margin: 0;
}
`;
const UserInfoWrapper = styled.div`
display: flex;
justify-content: space-between;
border-bottom: 1px solid #eeeeee;
`;
const Button = styled.button`
border: 0;
height: 20px;
background: none;
`
const Comment = () => {
const [input, setInput] = useState();
const { userData } = useContext(UserContext);
const [comments, setComments] = useState([]);
const onChange = (e) => {
setInput(e.target.value);
};
const addComment = () => { // 코멘트 추가
setComments(
comments.concat({
id: comments.length + 1,
content: input,
userName: userData[0].id,
})
);
setInput("");
};
const removeComment = (id) => { // 코멘트 삭제
return setComments(comments.filter((comment) => comment.id !== id));
};
const chagneContent = (id, inputWord) => { // 코멘트 수정
return setComments(comments.map((comment) => {
if (comment.id === id) {
return {
...comment,
content: inputWord,
};
}
return comment;
}));
};
return (
<div>
<input value={input} onChange={onChange}></input>
<button
onClick={() => {
addComment(input);
setInput("");
}}
>
댓글달기
</button>
{comments.map((comment, index) => (
<CommentWrapper key={`${comment.userName}_${index}`}>
<UserInfoWrapper>
<p>{comment.userName}</p>
<Button onClick={() => removeComment(comment.id)}>삭제</Button>
<Button onClick={() => chagneContent(comment.id, input)}>
수정
</Button>
</UserInfoWrapper>
내용: {comment.content}
</CommentWrapper>
))}
</div>
);
};
export default Comment;
우선 빈 배열인 comments를 상태로 관리해줍시다.
그리고 당연히 입력값이 필요한 input도 상태값으로 관리해줍니다.
또, 이전포스팅에 만들어둔 Login기능을 이용하여 현재 로그인 되어있는 사용자의 정보인 userData도 가져와주도록 합니다.
이제 재료는 준비가 끝났고 함수만 작성하면 끝입니다.
input의 프로퍼티중 하나인 onChane 내부에는 input값이 있어 e.target.value안에 입력한 값이 들어있습니다.
따라서 setInput을 이용하여 input의 값을 변경해주도록 합니다.
댓글 작성
const addComment = () => {
setComments(
comments.concat({
id: comments.length + 1,
content: input,
userName: userData[0].id,
})
);
};
<Button onClick={() => addComment()}> 을 통해 버튼을 누를시 addComment가 호출되도록 합니다.
그럼 배열함수인 concat을 통해 현재 배열의 길이에 1을 더하면 다음 id값이 담기고
content에는 현재 input상태값이 담기게되고
userName에는 userData의 id를 넣어주게되면 코멘트가 추가가 됩니다.
이렇게 코멘트를 추가하는 기능은 끝났습니다.
댓글 지우기
const removeComment = (id) => {
return setComments(comments.filter((comment) => comment.id !== id));
};
이번에는 코멘트를 지우는 함수 입니다.
배열 내장함수인 filter함수를 이용했습니다.
filter함수는 조건식에 맞는 아이템들만 리턴하여 새로운 배열을 만듭니다.
따라서 id가 2인 코멘트의 삭제버튼을 누른다면 id가 2인 코멘트를 제외한 나머지 배열만 comments에 담기게되니 삭제가 됩니다!
댓글 수정
const chagneContent = (id, inputWord) => {
setComments(comments.map((comment) => {
if (comment.id === id) {
return {
...comment,
content: inputWord,
};
}
return comment;
}));
setInput("");
};
이번에는 map함수를 이용하여 데이터를 수정해주었습니다.
우선 수정할 객체의 id값을 받아와야하니 id, 또 수정할 텍스트가 필요하니 inputWord를 인자로 받아줍시다.
map함수는 새로운 배열을 생성하므로 하나만 수정하면 전부 rerender가 되니 참고하세요!
우선 댓글의 정보인 comment객체의 id와 선택한 댓글인 id를 전부 비교합니다.
만약 선택한 id값이 배열에 담겨있는 comment와 같다면 스프레드연산자인 ... 을 이용하여 기존 프로퍼티는 그대로 복사해주고
content만 현재 input값으로 수정해주면 완성!
만약 같지않다면 그대로 리턴해주면 되기때문에 return comment를 해주면 끝입니다.