diff --git a/src/components/detail/CommentView.test.tsx b/src/components/detail/CommentView.test.tsx index 9e32b7c6..dbf5641e 100644 --- a/src/components/detail/CommentView.test.tsx +++ b/src/components/detail/CommentView.test.tsx @@ -10,14 +10,14 @@ describe('CommentView', () => { const renderCommentView = () => render(( )); context('댓글 작성자인 경우', () => { - given('user', () => PROFILE_FIXTURE); + given('userUid', () => PROFILE_FIXTURE.uid); describe('삭제 버튼을 클릭한다', () => { it('클릭 이벤트가 발생해야만 한다', () => { @@ -25,16 +25,15 @@ describe('CommentView', () => { fireEvent.click(screen.getByText('삭제')); - expect(handleRemove).toHaveBeenCalledWith(COMMENT_FIXTURE.commentId); + expect(handleRemove).toHaveBeenCalledWith({ + commentId: COMMENT_FIXTURE.commentId, groupId: COMMENT_FIXTURE.groupId, + }); }); }); }); context('댓글 작성자가 아닌 경우', () => { - given('user', () => ({ - ...PROFILE_FIXTURE, - uid: '1', - })); + given('userUid', () => '1'); it('삭제 버튼이 나타나지 않아야 한다', () => { const { container } = renderCommentView(); diff --git a/src/components/detail/CommentView.tsx b/src/components/detail/CommentView.tsx index 1160b072..eb479d58 100644 --- a/src/components/detail/CommentView.tsx +++ b/src/components/detail/CommentView.tsx @@ -5,7 +5,7 @@ import { import styled from '@emotion/styled'; import dayjs from 'dayjs'; -import { Profile } from '@/models/auth'; +import { DeleteCommentForm } from '@/hooks/api/comment/useDeleteComment'; import { Comment } from '@/models/group'; import { body1Font, body2Font, subtitle1Font } from '@/styles/fontStyles'; import { filteredWithSanitizeHtml } from '@/utils/filter'; @@ -15,17 +15,25 @@ import ProfileImage from '../common/ProfileImage'; interface Props { comment: Comment; - user: Profile | null; - onRemove: (commentId: string) => void; + userUid: string | undefined; + onRemove: ({ commentId, groupId }: DeleteCommentForm) => void; } +const commentViewPropsAreEqual = (prevProps: Props, nextProps: Props) => ( + prevProps.comment.commentId === nextProps.comment.commentId + && prevProps.userUid === nextProps.userUid + && prevProps.onRemove === nextProps.onRemove + && prevProps.comment.writer.uid === nextProps.comment.writer.uid + && prevProps.comment.groupId === nextProps.comment.groupId +); + function CommentView({ - comment, user, onRemove, + comment, userUid, onRemove, }: Props, ref: ForwardedRef): ReactElement { const { - writer, content, createdAt, commentId, + content, createdAt, commentId, groupId, writer, } = comment; - const isWriter = user?.uid === writer.uid; + const isWriter = userUid === writer.uid; return ( @@ -40,7 +48,7 @@ function CommentView({ {isWriter && ( onRemove(commentId)} + onClick={() => onRemove({ commentId, groupId })} > 삭제 @@ -52,7 +60,7 @@ function CommentView({ ); } -export default memo(forwardRef(CommentView)); +export default memo(forwardRef(CommentView), commentViewPropsAreEqual); const CommentStatus = styled.div` display: flex; diff --git a/src/components/detail/CommentsView.test.tsx b/src/components/detail/CommentsView.test.tsx index f81e0efd..5a50b0a5 100644 --- a/src/components/detail/CommentsView.test.tsx +++ b/src/components/detail/CommentsView.test.tsx @@ -1,5 +1,6 @@ import { fireEvent, render, screen } from '@testing-library/react'; +import useDeleteComment from '@/hooks/api/comment/useDeleteComment'; import useInfiniteFetchComments from '@/hooks/api/comment/useInfiniteFetchComments'; import COMMENT_FIXTURE from '../../../fixtures/comment'; @@ -8,6 +9,7 @@ import PROFILE_FIXTURE from '../../../fixtures/profile'; import CommentsView from './CommentsView'; jest.mock('@/hooks/api/comment/useInfiniteFetchComments'); +jest.mock('@/hooks/api/comment/useDeleteComment'); describe('CommentsView', () => { const handleRemove = jest.fn(); @@ -27,13 +29,16 @@ describe('CommentsView', () => { lastItemRef, }, })); + + (useDeleteComment as jest.Mock).mockImplementation(() => ({ + mutate: handleRemove, + })); }); const renderCommentsView = () => render(( )); @@ -53,7 +58,9 @@ describe('CommentsView', () => { fireEvent.click(screen.getByText('삭제')); - expect(handleRemove).toHaveBeenCalledWith(COMMENT_FIXTURE.commentId); + expect(handleRemove).toHaveBeenCalledWith({ + commentId: COMMENT_FIXTURE.commentId, groupId: COMMENT_FIXTURE.groupId, + }); }); }); }); diff --git a/src/components/detail/CommentsView.tsx b/src/components/detail/CommentsView.tsx index a47a7f3f..01247a7b 100644 --- a/src/components/detail/CommentsView.tsx +++ b/src/components/detail/CommentsView.tsx @@ -1,27 +1,31 @@ -import { memo, ReactElement } from 'react'; +import { ReactElement, useCallback } from 'react'; import styled from '@emotion/styled'; +import useDeleteComment, { DeleteCommentForm } from '@/hooks/api/comment/useDeleteComment'; import useInfiniteFetchComments from '@/hooks/api/comment/useInfiniteFetchComments'; -import { Profile } from '@/models/auth'; import { targetFalseThenValue } from '@/utils/utils'; import CommentSkeletonLoader from './CommentSkeletonLoader'; import CommentView from './CommentView'; interface Props { - user: Profile | null; + userUid: string | undefined; perPage: number; - onRemove: (commentId: string) => void; } -function CommentsView({ user, perPage, onRemove }: Props): ReactElement { +function CommentsView({ userUid, perPage }: Props): ReactElement { const { query: { data, isFetchingNextPage }, refState } = useInfiniteFetchComments({ perPage, }); + const { mutate: deleteCommentMutate } = useDeleteComment(perPage); const comments = data.pages; + const onRemoveComment = useCallback(( + commentForm: DeleteCommentForm, + ) => deleteCommentMutate(commentForm), []); + return ( {comments.map(({ items }) => ( @@ -31,8 +35,8 @@ function CommentsView({ user, perPage, onRemove }: Props): ReactElement { return ( @@ -46,7 +50,7 @@ function CommentsView({ user, perPage, onRemove }: Props): ReactElement { ); } -export default memo(CommentsView); +export default CommentsView; const CommentsViewWrapper = styled.div` & > div:last-of-type { diff --git a/src/components/home/TagsBar.tsx b/src/components/home/TagsBar.tsx index a51fd900..e19c7bdc 100644 --- a/src/components/home/TagsBar.tsx +++ b/src/components/home/TagsBar.tsx @@ -1,4 +1,4 @@ -import { memo, ReactElement } from 'react'; +import { ReactElement } from 'react'; import styled from '@emotion/styled'; import { useSetRecoilState } from 'recoil'; @@ -29,7 +29,7 @@ function TagsBar(): ReactElement { ); } -export default memo(TagsBar); +export default TagsBar; const TagsWrapper = styled.div` height: 36px; diff --git a/src/components/myInfo/SettingForm.tsx b/src/components/myInfo/SettingForm.tsx index 9824d5c3..5f8199a6 100644 --- a/src/components/myInfo/SettingForm.tsx +++ b/src/components/myInfo/SettingForm.tsx @@ -1,6 +1,4 @@ -import { - memo, ReactElement, useEffect, useState, -} from 'react'; +import { ReactElement, useEffect, useState } from 'react'; import { useForm } from 'react-hook-form'; import { useEffectOnce, useUpdateEffect } from 'react-use'; @@ -133,7 +131,7 @@ function SettingForm({ ); } -export default memo(SettingForm); +export default SettingForm; const MemberWithdrawalButton = styled(Button)` color: ${({ theme }) => theme.accent6}; diff --git a/src/containers/detail/CommentsContainer.test.tsx b/src/containers/detail/CommentsContainer.test.tsx index b9819674..fe74f66f 100644 --- a/src/containers/detail/CommentsContainer.test.tsx +++ b/src/containers/detail/CommentsContainer.test.tsx @@ -21,7 +21,7 @@ jest.mock('@/hooks/api/comment/useAddComment'); jest.mock('next/router', () => ({ useRouter: jest.fn().mockImplementation(() => ({ query: { - id: '1', + id: COMMENT_FIXTURE.groupId, }, })), })); @@ -90,7 +90,7 @@ describe('CommentsContainer', () => { expect(mutate).toHaveBeenCalledWith({ content: commentValue, writer, - groupId: '1', + groupId: COMMENT_FIXTURE.groupId, }); }); @@ -102,7 +102,7 @@ describe('CommentsContainer', () => { expect(mutate).toHaveBeenCalledWith({ commentId: COMMENT_FIXTURE.commentId, - groupId: '1', + groupId: COMMENT_FIXTURE.groupId, }); }); }); diff --git a/src/containers/detail/CommentsContainer.tsx b/src/containers/detail/CommentsContainer.tsx index e605a73a..e9d1284f 100644 --- a/src/containers/detail/CommentsContainer.tsx +++ b/src/containers/detail/CommentsContainer.tsx @@ -11,7 +11,6 @@ import CommentForm from '@/components/detail/CommentForm'; import CommentSkeletonLoader from '@/components/detail/CommentSkeletonLoader'; import useFetchUserProfile from '@/hooks/api/auth/useFetchUserProfile'; import useAddComment from '@/hooks/api/comment/useAddComment'; -import useDeleteComment from '@/hooks/api/comment/useDeleteComment'; import useFetchCommentCount from '@/hooks/api/comment/useFetchCommentCount'; import { GroupQuery } from '@/models'; import { CommentFields } from '@/models/group'; @@ -28,16 +27,11 @@ function CommentsContainer(): ReactElement { const { data: user } = useFetchUserProfile(); const { data: commentCount } = useFetchCommentCount(groupId); const { mutate: addCommentMutate } = useAddComment(perPage); - const { mutate: deleteCommentMutate } = useDeleteComment(perPage); const onSubmit = useCallback((commentForm: CommentFields) => addCommentMutate({ ...commentForm, groupId, - }), [groupId, addCommentMutate]); - - const onRemoveComment = useCallback((commentId: string) => deleteCommentMutate({ - commentId, groupId, - }), [groupId, deleteCommentMutate]); + }), [groupId]); return ( <> @@ -50,9 +44,8 @@ function CommentsContainer(): ReactElement { }> diff --git a/src/hooks/api/comment/useDeleteComment.ts b/src/hooks/api/comment/useDeleteComment.ts index 007d5b8c..3037fe23 100644 --- a/src/hooks/api/comment/useDeleteComment.ts +++ b/src/hooks/api/comment/useDeleteComment.ts @@ -11,7 +11,7 @@ import useCatchFirestoreErrorWithToast from '../useCatchFirestoreErrorWithToast' import { deleteCommentQueryData } from './queryDataUtils'; -type DeleteCommentForm = { +export type DeleteCommentForm = { commentId: string; groupId: string; };