👩🏻💻 Today Learn
🤦🏻♀️ 고민한 부분
supabase를 사용하면서 typescript+next.js를 이용하여 댓글기능을 만드는건 어려움이 많았다 하하..
우선 데이터를 가져오고, 삭제하고, 업데이트하는 api는 supabase 문서에 친절하게 나와있었다.
// 리뷰 댓글 가져오기
export const fetchReviewComment = async () => {
const fetchReviewCommentQuery = await supabase
.from('review_comment')
.select('*, profiles(*)')
.returns<Tables<'review_comment'>[]>();
const {data: fetchReviewCommentData, error} = fetchReviewCommentQuery;
return {data: fetchReviewCommentData, error};
};
// 리뷰 댓글 추가하기
export const addReviewComment = async (userId: string, comment: string, reviewId: number) => {
return await supabase
.from('review_comment')
.insert({user_id: userId, content: comment, review_id: reviewId})
.select();
};
// 리뷰 댓글 삭제하기
export const deleteReviewComment = async (id: number) => {
return await supabase.from('review_comment').delete().eq('id', id);
};
// 리뷰 댓글 수정하기
export const updateReviewComment = async ({id, editingComment}: {id: number; editingComment: string}) => {
return await supabase.from('review_comment').update({content: editingComment}).eq('id', id).select();
};
const {data: reviewCommentData} = useQuery({
queryKey: ['fetchReviewCommentList'],
queryFn: fetchReviewComment,
refetchOnWindowFocus: false,
staleTime: 3000,
});
const addCommentMutate = useMutation({
mutationFn: async () => await addReviewComment(userId, comment, reviewId),
onSuccess: () => {
queryClient.invalidateQueries({queryKey: ['fetchReviewCommentList']});
},
});
const deleteCommentMutate = useMutation({
mutationFn: deleteReviewComment,
onSuccess: () => {
queryClient.invalidateQueries({queryKey: ['fetchReviewCommentList']});
},
});
const updateCommentMutate = useMutation({
mutationFn: updateReviewComment,
onSuccess: () => {
queryClient.invalidateQueries({queryKey: ['fetchReviewCommentList']});
},
});
여기서 쿼리키 틀리지 않게 조심하자! (대충 난 잘못써서 안됐던 경험이 있다는 뜻..)
// 댓글 등록하기
const commentSubmitHandler = async () => {
if (!comment) {
warnTopCenter({message: '댓글을 입력해주세요', timeout: 2000});
return;
}
if (userId === '') {
warnTopCenter({message: '로그인 후 댓글 작성이 가능합니다', timeout: 2000});
return;
}
try {
await addCommentMutate.mutate();
successTopCenter({message: '댓글을 등록하였습니다', timeout: 2000});
} catch (error) {
console.log('reviewCommentError', error);
errorTopCenter({message: '댓글 등록이 실패하였습니다', timeout: 2000});
}
};
팀원분이 toastify 훅을 만들어주셔서 한줄씩만 추가해주면 손쉽게 사용할 수 있었다.
// 삭제버튼 클릭
const deleteButtonHandler = (id: number) => {
Swal.fire({
title: '정말로 삭제하시겠습니까?',
text: '삭제하면 되돌릴 수 없습니다',
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#83e0a5',
cancelButtonColor: '#b0b0b0',
confirmButtonText: 'Yes',
}).then((result): void => {
if (result.isConfirmed) {
Swal.fire({
title: '삭제되었습니다',
icon: 'success',
});
deleteCommentMutate.mutate(id);
} else {
return;
}
});
};
Sweet Alert2를 활용하여 confirm을 해서 그렇지 사실 핵심은 else윗줄 mutate
부분이다.
수정하는 부분을 가장 헤맸다 ㅠㅠ
우선 수정을 클릭하기 전에는 수정 | 삭제
형태였다가 수정을 클릭하면 취소 | 완료
상태로 바꾸는 조건부렌더링을 사용하려다보니 조금 헤맸던것 같기도 하고..
다 해봤던 기능이지만 Typescript 이놈이 골치아팠다.
// 수정완료버튼 클릭
const completeButtonHandler = async (id: number) => {
if (editingComment === currentComment) {
warnTopCenter({message: '변경된 내용이 없습니다', timeout: 2000});
return;
}
try {
await updateCommentMutate.mutate({id, editingComment});
setEditingComment(editingComment);
setIsEdit(!isEdit);
successTopCenter({message: '수정이 완료되었습니다', timeout: 2000});
} catch (error) {
console.log('updateCommentError', error);
errorTopCenter({message: '댓글 수정이 실패하였습니다', timeout: 2000});
}
};
수정된 부분이 없을 시에 알려주고 수정된 부분이 있으면 바로 update가 완료되는것도 확인하였다.
✍🏻 회고
CRUD는 가장 기본적인 기능인데 왜 늘 할때마다 새로운지... 이전에 했던 코드를 보면서 해보려고 하는데 '내가 짠건데 이걸 어떻게 했었지?' 하는 생각과 함께 다시 분석하고 적용하는것에 시간이 꽤 많이 걸린다.
뭐 역시나 반복만이 답이겠지