• 카테고리

    질문 & 답변
  • 세부 분야

    풀스택

  • 해결 여부

    미해결

강좌 끝나고 댓글 수정 기능 만들어 보고 있습니다

23.09.26 15:12 작성 조회수 193

0

{commentFormOpened && (
  <div>
    {commentEditMode
      ?
        <CommentContent post={post} commentEditMode={commentEditMode} onClickUpdateComment={onClickUpdateComment} onCancelUpdateComment={onCancelUpdateComment} />
      : (
          <>
            <CommentForm post={post} />
            <CommentContent post={post} commentEditMode={commentEditMode} onClickUpdateComment={onClickUpdateComment} onCancelUpdateComment={onCancelUpdateComment} />
          </>
        )
    }
  </div>
)}

//PostCard.js

 

 

import React, { useCallback, useEffect, useState } from 'react';
import { Avatar, Comment, List, Input, Button, Popover } from 'antd';
import { useDispatch, useSelector } from 'react-redux';
import Link from 'next/link';
import PropTypes from 'prop-types';
import { EllipsisOutlined } from '@ant-design/icons';

import { UPDATE_COMMENT_REQUEST } from '../reducers/post';


const {TextArea} = Input;

const CommentContent = ({ post, onCancelUpdateComment, commentEditMode, onClickUpdateComment }) => {
  const dispatch = useDispatch();
  const id = useSelector((state) => state.user?.me.id);
  const { updateCommentLoading, updateCommentDone } = useSelector((state) => state.post);
  const [editText, setEditText] = useState(post.Comments.content);

  useEffect(() => {
    if (updateCommentDone) {
      onCancelUpdateComment();
    }
  }, [updateCommentDone]);

  const onChangeCommentText = useCallback((e) => {
    setEditText(e.target.value);
  }, []);

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


  return (
    <div>
      {commentEditMode
        ? (
          <>
            <TextArea value={editText} onChange={onChangeCommentText} />
            <Button.Group>
              <Button loading={updateCommentLoading} onClick={onChangeComment}>수정</Button>
              <Button type="danger" onClick={onCancelUpdateComment}>수정 취소</Button>
            </Button.Group>
          </>
        )
        :
        <List
          header={`${post.Comments.length}개의 댓글`}
          itemLayout="horizontal"
          dataSource={post.Comments}
          renderItem={(item) => (
            <li>
              <Comment
                actions={[<Popover
                  key="more"
                  content={
                    <Button.Group>
                      {id && item.User.id === id ? (
                        <>
                          <Button onClick={onClickUpdateComment}>수정</Button>
                          <Button type="danger">
                            삭제
                          </Button>
                        </>
                      ) : (
                        <Button>신고</Button>
                      )}
                    </Button.Group>
                  }
                >
                  <EllipsisOutlined />
                </Popover>,]}
                author={item.User.nickname}
                avatar={
                  <Link href={`/user/${item.User.id}`}>
                    <a><Avatar>{item.User.nickname[0]}</Avatar></a>
                  </Link>
                }
                content={item.content}
              />
            </li>
          )}
        />
      }
    </div>
  )
}

CommentContent.propTypes = {
  post: PropTypes.shape({
    id: PropTypes.number.isRequired,
    Comments: PropTypes.arrayOf(PropTypes.shape({
      id: PropTypes.number.isRequired,
      content: PropTypes.string.isRequired,
    }))
  }),
  onCancelUpdateComment: PropTypes.func.isRequired,
  onClickUpdateComment: PropTypes.func.isRequired,
  commentEditMode: PropTypes.bool
};

CommentContent.defaultsProps = {
  commentEditMode: false,
}

export default CommentContent;

//CommentContent.js

 

case UPDATE_COMMENT_REQUEST:
  draft.updateCommentLoading = true;
  draft.updateCommentDone = false;
  draft.updateCommentError = null;
  break;
case UPDATE_COMMENT_SUCCESS:
  draft.updateCommentLoading = false;
  draft.updateCommentDone = true;
  const post = draft.mainPosts.find((v) => v.id === action.data.PostId);
  post.Comments = post.Comments.find((v) => v.id === action.data.CommentId);
  post.Comments = post.Comments.find((v) => v.id === action.data.UserId);
  post.Comments.content = action.data.content;
  break;
case UPDATE_COMMENT_FAILURE:
  draft.updateCommentLoading = false;
  draft.updateCommentError = action.error;
  break;

//reducers/post.js

 

function updateCommentAPI(data) {
  return axios.patch(`/post/${data.PostId}/comment`, data);
}

function* updateComment(action) {
  try {
    const result = yield call(updateCommentAPI, action.data);
    yield put({
      type: UPDATE_COMMENT_SUCCESS,
      data: result.data,
    });
  } catch (err) {
    console.error(err);
    yield put({
      type: UPDATE_COMMENT_FAILURE,
      error: err.response.data,
    });
  }
}

// sagas/post.js

 

router.patch('/:postId/comment', isLoggedIn, async (req, res, next) => { // PATCH post/2/comment
  try {
    await Comment.update({
      content: req.body.content,
    }, {
      where: {
        PostId: req.params.postId,
        UserId: req.user.id,
      },
    });
    res.status(200).json({
      PostId: parseInt(req.params.postId, 10),
      UserId: req.user.id,
      content: req.body.content,
    });
  } catch (error) {
    console.error(error);
    next(error);
  }
});

//routes/post.js

K-035.png

이렇게 PostId, UserId, content가 보내지고, 실패가 뜨면서 새로고침을 하면 해당 글에 달았던 댓글들이 모두 다 "zzz"로 변경되어 있습니다. 그래서 CommentId를 보내줘야 될 거 같은데 여기서 막혀서 감이 도무지 잡히질 않습니다.

 

 

답변 1

답변을 작성해보세요.

0

지금 댓글창 자체를 댓글수정창으로 재사용하고 계신 것 같은데 commentEditMode를 true로 바꿀 때 commentId도 같이 redux에 저장해두세요.

아니면 댓글 수정창을 따로 Comment component에 만드시면 됩니다. Comment 컴포넌트에서는 comment.id에 접근 가능하게 되니까요.

서버에서는 where: { id: commentId } 이런 식으로 특정 comment만 타겟해서 수정해야 합니다.

 

리듀서 부분도 다음과 같이 하나만 찾아서 수정해야 합니다.

const comment = post.Comments.find((v) => v.id === action.data.CommentId);
comment.content = action.data.content;

 

답변 감사합니다. commentEditMode를 true로 바꿀 때 commentId도 같이 redux에 저장하라고 하셨는데 이해가 잘 안가서 힌트 좀만 더 주실 수 있으신가요?

수정 버튼을 누를 때 그 버튼에 딸린 commentId를 같이 redux로 보내시면 됩니다. 지금 CommentForm이랑 Comment 컴포넌트 분리되어 있나요?

네 분리되어 있습니다.

그러면 Comment 컴포넌트에서 comment.id 접근 가능하실테니 그걸 redux로 보내시면 됩니다.

넵 감사합니다