🤍 전 강의 25% 할인 중 🤍

2024년 상반기를 돌아보고 하반기에도 함께 성장해요!
인프런이 준비한 25% 할인 받으러 가기 >>

  • 카테고리

    질문 & 답변
  • 세부 분야

    풀스택

  • 해결 여부

    미해결

댓글 삭제 기능 오류 발생

21.08.29 12:39 작성 조회수 274

1

제로초 선생님 강의를 듣고 나서 댓글 삭제 기능과 수정 기능 및 좋아요 갯수를 세는 기능 등을 만들어보고 있는데 아직 실력이 부족해서 그런지 상당히 헷갈리네요. 나머지는 추가로 해보려고 하고 댓글 삭제 기능만 먼저 질문드리겠습니다..!

CommentEditForm.js

...
import CommentRemoveBtn from './CommentRemoveBtn';

const { TextArea } = Input;
const CommentEditForm = ({ post }) => {
    const dispatch = useDispatch();
    const id = useSelector((state=> state.user.me?.id);
    const [editTextsetEditText] = useState('');
    const [commentEditModesetCommentEditMode] = useState(false);
    const onReviseCommentText = useCallback((e=> {
      setEditText(e.target.value);
    });
    const { reviseCommentLoading } = useSelector((state=> state.post);

    const onReviseComment = useCallback((CommentId=> () => {
        dispatch({
            type: REVISE_COMMENT_REQUEST,
            data: {
                content: editText,
                PostId: post.id,
                UserId: id,
                CommentId,
            },
        });
    }, [editTextid]);

    const onRemoveComment = useCallback((CommentId=> () => {
        if (!id) {
            return alert('로그인이 필요합니다');
        }
        return dispatch({
          type: REMOVE_COMMENT_REQUEST,
          data: {
            CommentId,
            PostId: post.id,
          },
        });
    }, [post.id]);

    const onClickReviseComment = useCallback(() => {
        setCommentEditMode(true);
    });

    const onCancelReviseComment = useCallback(() => {
        setCommentEditMode(false);
    }, []);

    return (
        <div>
          {commentEditMode
          ? (
            <>
              <TextArea value={editText} onChange={onReviseCommentText} />
              <Button.Group>
                <Button loading={reviseCommentLoading} onClick={onReviseComment}>수정</Button>
                <Button type="danger" onClick={onCancelReviseComment}>취소</Button>
              </Button.Group>        
            </>
          )
          : (
            <List
            header={`${post.Comments.length}개의 댓글`}
            itemLayout="horizontal"
            dataSource={post.Comments || []}
            renderItem={(item=> (
                <li>
                    <Comment
                        actions={id && item.User.id === id 
                        ? [
                        <div style={fontSize: '13px'marginRight: '10px' }}>
                            {moment(item.createdAt).format('MM.DD HH:mm')}
                        </div>,
                        <span style={fontSize: '13px' }} onClick={onClickReviseComment}>
                            수정하기
                        </span>,
                        <CommentRemoveBtn onRemoveComment={onRemoveComment(item.id)} />,
                        ]
                        : [
                        <div style={fontSize: '13px'marginRight: '10px' }}>
                            {moment(item.createdAt).format('MM.DD HH:mm')}
                        </div>,
                        ]}
                        author={item.User.nickname}
                        avatar={(
                        <Link href={`/user/${item.User.id}`} prefetch={false}>
                            <a><Avatar>{item.User.nickname[0]}</Avatar></a>
                        </Link>
                        )}
                        content={item.content}
                    />
                </li>
            )}
            />
            )}
        </div>
    );
};

CommentEditForm.propTypes = {
    post: PropTypes.object.isRequired,
};
  
export default CommentEditForm;

댓글 삭제 기능을 구현하기 위해서 onRemoveComment 이벤트를 만들고, '삭제하기' 버튼을 누르면 REMOVE_COMMENT_REQUEST가 실행되면서 PostId와 CommentId를 넘겨주었습니다.

reducers/post.js

    case REMOVE_COMMENT_REQUEST:
      draft.removeCommentLoading = true;
      draft.removeCommentDone = false;
      draft.removeCommentError = null;
      break;
    case REMOVE_COMMENT_SUCCESS: {
      const post = draft.mainPosts.find((v=> v.id === action.data.PostId);
      draft.removeCommentLoading = false;
      draft.removeCommentDone = true;
      draft.mainPosts = post.Comments.filter((v=> v.id !== action.data.CommentId);
      break;
    }
    case REMOVE_COMMENT_FAILURE:
      draft.removeCommentLoading = false;
      draft.removeCommentError = action.error;
      break;

routes/post.js

router.delete('/:postId/comment'isLoggedInasync (reqresnext=> {   // DELETE /post/1/comment
    try {
        const comment = await Comment.findOne({ where: { PostId: req.params.postIdUserId: req.user.id } });
        await Comment.destroy({
            where: { id: comment.id },
            include: [{
                model: User,
                attributes: ['id''nickname'],
            }],
        });
        res.status(200).json({ id: comment.idPostId: parseInt(req.params.postId10), UserId: req.user.id });
    } catch (error) {
        console.error(error);
        next(error);
    }
});

리듀서와 라우터는 위와 같이 만들었는데, db에서는 정상적으로 댓글이 지워지지만 화면에서는 반영이 안됩니다.

 

확실히 리듀서 코드를 잘못 짜줬기 때문에 위와 같이 댓글뿐만 아니라 다른 것까지 다 지워버리는 현상이 발생하는 것 같은데,  mainPosts라는 배열 안에 객체가 있고, 그 안에 Comments가 또 배열 객체를 가지고 있다보니 이를 지우는 것이 매우 헷갈리는 것 같습니다.

    case REMOVE_COMMENT_REQUEST:
      draft.removeCommentLoading = true;
      draft.removeCommentDone = false;
      draft.removeCommentError = null;
      break;
    case REMOVE_COMMENT_SUCCESS: {
      const post = draft.mainPosts.find((v=> v.id === action.data.PostId);
      draft.removeCommentLoading = false;
      draft.removeCommentDone = true;
      draft.mainPosts = post.Comments.filter((v=> v.id !== action.data.CommentId);
      break;
    }
    case REMOVE_COMMENT_FAILURE:
      draft.removeCommentLoading = false;
      draft.removeCommentError = action.error;
      break;

이 리듀서를 어떻게 수정하는 것이 좋을까요..?

답변 1

답변을 작성해보세요.

0

post.Comments = podt.Comments.filter.... 이런 식으로 하면 됩니다. mainpost를 바꾸는게 아니라 post 안의 comments만 바꾸면 되니까요

ㅠㅠㅠ 감사합니다 해결했습니다!

그런데 혹시 대댓글 기능은 어떻게 구현해야할지 알 수 있을까요? 대댓글은 제가 이해하기론 Comment 테이블과 Comment 테이블이 관계되는 것 같은데...하나의 부모 댓글이 여러개의 대댓글을 가질 수 있으니깐 1:다 관계일거고, 그러면 Comment와 Comment 테이블 간의 관계가 아니라 ReComment 테이블을 만들어서 Comment 테이블과 1:다 관계를 맺어주면 되려나요?!

대댓글은 방법이 다양합니다. 인스타그램이나 페이스북처럼 뎁스가 깊어지지는 않고 @로 해결하는 곳이 있고(이건 그냥 postId에 해당하는 댓글을 전부 다 가져오면 됩니다), 진짜 뎁스를 깊게 가져가는 곳이 있습니다.

뎊스가 깊어지는 곳은 댓글들을 불러온 뒤 다시 조립하는 과정이 필요한데요. join으로 해결하기엔 너무 복잡합니다. 제 블로그의 댓글 데이터는 컬럼 하나에 자식 댓글들 아이디에 대한 배열을 데이터로 갖고 있습니다. 그래서 전체 댓글을 불러온 뒤 컬럼에 든 아이디를 보고 프론트 단에서 조립합니다.

감사합니다! 시도해보겠습니다!

채널톡 아이콘