본문 바로가기

트러블 슈팅/React

[React-Query] 대댓글 기능 중 댓글 삭제 시 해당 대댓글 다시 불러오는 현상 해결

주요 기능

지금 현재하는 프로젝트에서 댓글을 수정, 삭제, 답글을 달 수 있는 기능이 있다. 

주요 기능을 설명하자면,

1. 댓글 등록 기능

2. 등록된 댓글 수정, 삭제, 대댓글 등록 가능

3. 대댓글 등록 시 수정, 삭제 기능 

4. 각 기능 별로 바뀌는 탭 바

 

문제 사항

이런 식으로 구현이 되는데, 댓글 조회, 수정, 삭제, 등록, 상태별 바뀌는 탭 바는 최상위 부모 컴포넌트에서 제작을 하였다.  그래서 컴포넌트의 구조가 Comment->CommentList->CommentItem->ReplyCommentList->ReplyCommentItme 으로 구성이 되어 있는데,

댓글 조회:Commnet, 대댓글 조회:ReplyCommentList로 불러온다. 이때 댓글을 조회,수정,삭제는 상단에서 관리해서 수월했지만, 대댓글의 경우에는 수정, 삭제 시 즉시 반영되어야 했기 때문에 아래 코드처럼 작성했다.

 

useEffect()를 사용해서 수정,삭제 성공 시 refetch()가 발생되도록 수동적으로 제어를 해주었다. 하지만, React-Query를 이용하여, 자동적으로 제어를 해주고 싶었다.

export const ReplyCommentList = ({ ...props }: Props) => {

  const { data: replyData, refetch } = useGetReplyComment({
    commentId: props.commentData.commentId,
  });
 
  useEffect(() => {
    if (props.isSuccess) {
      refetch()
      props.onSaveIsSuccess(false);
    }
  }, [props.isSuccess]);

  return (
    <S.Layout>
      {replyData &&
        replyData.content.map((r, index) => (
          <Fragment key={r.commentId}>
            {<ReplyCommentItem replyData={r} {…props} />}
            {replyData.content.length !== index + 1 && (
              <hr className="line_box" />
            )}
          </Fragment>
        ))}
      {replyData && !replyData.last && (
        <Pagination text="댓글 더보기" onClick={handleClickPage} />
      )}
    </S.Layout>
  );
};

 

 

해결 과정

React-Query에서 invalidateQueries가 있다는 것을 알게 되었다.

invalidateQueries

invalidateQueries는 화면을 최신 상태로 유지하는 방법 중 하나이다. 아래처럼 작성을 하게 되면 해당 키를 강제로 쿼리를 무효화시키고 다시 가져오게 된다. 

import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";

const useAddSuperHeroData = () => {
  const queryClient = useQueryClient();
  return useMutation(addSuperHero, {
    onSuccess(data) {
      queryClient.invalidateQueries({ queryKey: ["super-heroes"] }); // 이 key에 해당하는 쿼리가 무효화!
      console.log(data);
    },
    onError(err) {
      console.log(err);
    },
  });
};

 

해결 1

그래서 이점을 이용해서 처음에는 공통된 키를 제작하였다. 

const COMMENT_API_KEY = {
  COMMENT: 'comment', //댓글, 대댓글 포함
  NEW_COMMENT: 'newComment', //댓글
  REPLY_COMMENT: 'replyComment', //대댓글
};

 

아래는 댓글이나 대댓글을 삭제 했을 때 실행되는데, key를 COMMENT를 두어서 댓글, 대댓글을 다 refetch하게 설정해놓았다.

const queryClient = useQueryClient();
  return useMutation(deleteNewComment, {
    onSuccess: () => {
      queryClient.invalidateQueries([COMMENT_API_KEY.COMMENT])
    },

그러니깐 또 다른 문제가 발생하였는데, 대댓글을 삭제 했을 때는 잘 작동하지만, 댓글을 삭제했을 경우에는 댓글은 다시 삭제하고 난 댓글을 다시 refetch를 해오는데, 대댓글의 경우에는 삭제된 댓글의 대댓글까지 불러와서 오류가 났다.

 

해결 2

공통 key인 COMMENT를 삭제하고,  the()매서드를 이용하여, 순차적으로 댓글을 불러오는데 성공하면, 대댓글을 불러오는 식으로 수정하였다.

const useDeleteNewComment = () => {
  const queryClient = useQueryClient();
  return useMutation(deleteNewComment, {
    onSuccess: () => {
      queryClient.invalidateQueries([COMMENT_API_KEY.NEW_COMMENT]).then(() => {
        queryClient.invalidateQueries([COMMENT_API_KEY.REPLY_COMMENT]);
      });
    },

    /** @TODO 나중에 error boundary 추가 */
    onError: (e) => console.log(e),
  });
};

 그런데 계속해서 똑같은 오류가 발생했다. 그래서 Query Dev Tool을 이용해서 살펴 보았다. 살펴보니 대댓글을 등록하면,[replyComment,commentId]가 같이 캐시되는 모습을 확인 할 수 있는데, 삭제된 commentId도 같이 캐시되다보니, 댓글이 삭제되어도 해당 commentId의 댓글도 같이 불러왔던 거였다.

const useGetReplyComment = ({
  commentId,
  pageCount,
}: Props): UseQueryResult<Page<GetReplyComment>> => {
  return useQuery(
    [COMMENT_API_KEY.REPLY_COMMENT, commentId], //commentid도 같이 캐시
    () => getReplyComment({ commentId, pageCount }),
    { enabled: !!commentId },
  );
};

 

최종 해결 방안

그래서 이 점을 해결하고자, 모든 replyComment 캐시를 삭제하고 다시 불러오는 식으로 구현을 해야겠다고 생각이 들어서 엑세스  가능한 쿼리를 제거할 때 사용하는 함수인 removeQueries를 이용더니, 오류없이 잘 작동하는 모습을 확인 할 수 있었다.

const useDeleteNewComment = () => {
  const queryClient = useQueryClient();
  return useMutation(deleteNewComment, {
    onSuccess: () => {
      queryClient.invalidateQueries([COMMENT_API_KEY.NEW_COMMENT]).then(() => {
        queryClient.removeQueries([COMMENT_API_KEY.REPLY_COMMENT]);
      });
    },

    /** @TODO 나중에 error boundary 추가 */
    onError: (e) => console.log(e),
  });
};

 

추 후 페이지네이션을 적용하면서 해당 로직이 변경되었습니다.

자세한 내용은 아래를 참고해주세요!

 

[React] useInfiniteQuery로 페이지네이션 적용하고 난 후 데이터 깜빡임 현상

페이지네이션 적용하고 난 후 Cache된 데이터가 보이는 현상 처음에는 removeQueries key값 하나만 주고, 댓글을 삭제하면 Cache된 곳에서 대댓글을 다 삭제하게 로직을 재구성했었다. 곰곰히 생각해보

dev-logbook.tistory.com