주요 기능
지금 현재하는 프로젝트에서 댓글을 수정, 삭제, 답글을 달 수 있는 기능이 있다.
주요 기능을 설명하자면,
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
'트러블 슈팅 > React' 카테고리의 다른 글
[React-Query] react-query useInfiniteQuery를 이용해서 페이지네이션 개선하기 (1) | 2023.12.07 |
---|---|
[React] useInfiniteQuery page별로 받아오는 데이터 병합하기 (0) | 2023.12.06 |
[React] useCallback을 왜 제거할까? (0) | 2023.11.29 |
[react-query] 실행 시점 enabled, refetch를 이용하고, cache된 데이터 삭제 (1) | 2023.11.24 |
[React+Typescript]key of type of (icons)의 string 오류 (0) | 2023.09.01 |