댓글기능에 답글 기능을 추가하고 수정, 삭제 테스트를 하는데 답글의 경우 삭제가 잘 되지만 부모인 댓글의 경우 삭제가 되지 않았다.
또한 답글이 있는 부모댓글을 삭제했을때 해당 댓글과 답글까지 싹다 삭제하는지? or 댓글만 "삭제된 댓글입니다." 로 내용을 바꾸어야 할지? 혼자 판단하면 안될 것 같은 부분도 있어서 팀원과 논의하였고, 전체 삭제하기보다 부모댓글만 "삭제된 댓글입니다." 로 표시하도록 하기로 결정했다.
처음엔 mutation 함수에서 무작정 코드를 써보다가 코드가 너무나 길어져서 나조차도 자꾸 헷갈렸고, 게다가 의도한대로 동작하지도 않아서 결국 작성했던 코드들을 다 지운 뒤 댓글/답글 삭제 관련해서 일어날 수 있는 경우들을 차근차근 적어봤다.
부모댓글
- 부모댓글 삭제 시 답글이 없는경우 → 바로 삭제
- 부모댓글 삭제 시 답글이 있는경우 → is_deleted : false 로 변경 / ui 에서는 “삭제된 댓글입니다” 보여주기
답글
- 답글 삭제 시 + is_deleted : false / true 이건 상관없음 → 답글만 바로 삭제
- 답글 삭제 시 답글이 1개인경우 + 부모댓글이 is_deleted : true 인 경우 → 부모댓글이랑 같이 삭제 ★
구현해보기
① comment 테이블에 is_deleted : false (default) 컬럼 생성
답글이 존재하는 부모댓글을 삭제했을 때 "삭제된 댓글입니다" 를 보여주기 위해선 db 상에서 해당 댓글을 삭제하는 것이 아닌, 기본값이 false 인 is_deleted 컬럼을 추가해 해당 댓글 상태를 관리하고자 했다.
② 부모댓글(답글 ㅇ) 삭제 시 삭제상태로 변경하는 로직 생성
post 테이블에서 comment_count 컬럼을 생성해 답글 생성/삭제에 따라 카운팅 값을 넣어달라는 팀원의 요청이 있었다.
그래서 내부로직에 is_deleted = true 로 변경하고 comment_count -1 해주는 로직을 추가했다.
그외의 경우에는 supabase 에서 트리거를 만들어서 적용했다.
(적용한 트리거)
- 댓글/답글 추가 comment_count +1
- 답글이 있는 부모 댓글이 db에서 삭제될땐 comment_count 변동 X
- 답글 없는 부모댓글, 답글 삭제 시 comment_count -1
// 답글이 존재하는 부모댓글 삭제시 삭제상태로 변경
export const updateStateToDelete = async (
comment_id: string,
postId: string,
) => {
// comment 테이블 업데이트
const { error: commentError } = await browserClient
.from("comment")
.update({
is_deleted: true,
})
.eq("comment_id", comment_id);
if (commentError) {
throw new Error("삭제 상태 변경에 실패했습니다.");
}
// 현재 comment_count 조회
const { data: post } = await browserClient
.from("post")
.select("comment_count")
.eq("post_id", postId)
.single();
if (!post) {
throw new Error("댓글을 찾을 수 없습니다.");
}
// post 테이블의 comment_count 감소
const { error: postError } = await browserClient
.from("post")
.update({
comment_count: post.comment_count - 1,
})
.eq("post_id", postId);
if (postError) {
throw new Error("댓글 카운트 감소에 실패했습니다.");
}
};
③ 기존에 생성한 삭제 mutation 함수는 유지하면서 is_deleted 상태를 변경하는 mutation 함수 생성
// 댓글 삭제
export const useDeleteCommentMutation = (postId: string) => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: deletePostComment,
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["comment", postId],
});
},
});
};
// 답글이 존재하는 부모댓글 삭제 시 is_deleted 상태 변경
export const useUpdateStateToDelete = (postId: string) => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (commentId: string) => updateStateToDelete(commentId, postId),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["comment", postId],
});
},
});
};
④ 컴포넌트에서 사용 + 댓글/답글별 유효성 적용
삭제 로직을 handleDeleteClick 함수로 분리해서 삭제 버튼에 onClick으로 넣어주었다.
위에서 정리한 경우의 수들을 조건을 주어 하나씩 처리되도록 해주었다.
// 댓글 삭제 / 부모댓글 상태(삭제)변경 / 수정
const { mutate: deleteComment } = useDeleteCommentMutation(
`${comment.post_id}`,
);
const { mutate: updateParentState } = useUpdateStateToDelete(
`${comment.post_id}`,
);
const findParentComment = (parentId: string) => {
return commentList.find((c) => c.comment_id === parentId);
};
const handleDeleteClick = () => {
const isConfirmed = window.confirm("댓글을 삭제하시겠습니까?");
if (!isConfirmed) return;
// 부모댓글
if (!isReply) {
if (!hasReplies) {
// 답글X -> 바로삭제
deleteComment(comment.comment_id);
return;
} else {
// 답글O -> is_deleted: true 로 상태변경
updateParentState(comment.comment_id);
return;
}
}
// 답글인 경우
const parentComment = comment.parent_id
? findParentComment(comment.parent_id)
: null;
if (parentComment?.is_deleted && parentComment.replies?.length === 1) {
// 부모가 삭제 상태이고 마지막 답글인 경우 -> 부모댓글도 함께 삭제
deleteComment(comment.comment_id, {
onSuccess: () => {
deleteComment(parentComment.comment_id);
},
});
return;
} else {
// 그 외의 경우 -> 해당 답글만 삭제
deleteComment(comment.comment_id);
return;
}
};
// 답글 존재 여부 확인
const hasReplies = !!comment.replies?.length;
🚨 발생했던 문제
부모댓글이 삭제 상태이고, 답글이 마지막 답글인 경우 부모댓글도 함께 삭제가 되어야하는데 계속 답글만 삭제가 되고 부모댓글 삭제 함수가 실행되지 않았다.
❓ 원인
함수가 실행이 되지 않는 이유를 알기 위해 실행부 사이사이에 콘솔을 추가하고 에러 메세지도 나오도록 추가해서 확인해보니 데이터베이스의 참조 무결성(foreign key constraint) 때문에 발생하는 문제임을 확인할 수 있었다.
부모댓글의 comment_id 를 참조하고 있는 답글이 완전히 삭제되지 않았는데 부모댓글까지 같이 삭제하려고 하니 발생한 오류였다.
✅ 해결방법
답글이 성공적으로 삭제가 된 후 부모 댓글을 삭제하도록 onSuccess 안으로 로직을 넣어주었고, 정상적으로 삭제가 되는 것을 확인할 수 있었다!
// (수정 전 코드)
if (parentComment?.is_deleted && parentComment.replies?.length === 1) {
// 부모가 삭제 상태이고 마지막 답글인 경우 -> 부모댓글도 함께 삭제
deleteComment(comment.comment_id);
console.log("답글 삭제!");
deleteComment(parentComment.comment_id);
console.log("부모 댓글 삭제!");
return;
}
// (수정 후 코드)
if (parentComment?.is_deleted && parentComment.replies?.length === 1) {
// 부모가 삭제 상태이고 마지막 답글인 경우 -> 부모댓글도 함께 삭제
deleteComment(comment.comment_id, {
onSuccess: () => {
deleteComment(parentComment.comment_id);
},
});
return;
}
🧐 느낀점
조건들을 삭제함수에 넣어서 처리를 해주었는데, 좀 더 괜찮은 방법도 있지않을까..? 다른 코드들도 다양하게 접해봐야 생각을 확장할 수 있을 것 같다 생각이 들고, 앞으로 다른 코드들을 볼 때 유효성 처리를 어떻게 하는지 자세히 살펴봐야겠다.
'TIL' 카테고리의 다른 글
shadcn/ui 캘린더 css 적용하기 (0) | 2024.11.06 |
---|---|
[Refactoring] 바텀시트 재사용 컴포넌트로 분리하기 (0) | 2024.11.05 |
캘린더 일정관리 - 일정 시간 중복 체크 유효성 ② (0) | 2024.11.03 |
캘린더 일정관리 - 일정 시간 중복 체크 유효성 ① (0) | 2024.11.01 |
캘린더 일정관리 - 시작시간 / 종료시간 유효성 (0) | 2024.10.31 |