diff --git a/src/components/epigram/Comment/CommentList.tsx b/src/components/epigram/Comment/CommentList.tsx index 5a605fe9..9d06bd9c 100644 --- a/src/components/epigram/Comment/CommentList.tsx +++ b/src/components/epigram/Comment/CommentList.tsx @@ -1,27 +1,66 @@ -import useEpigramCommentsQuery from '@/hooks/useEpigramCommentHook'; +import React, { useEffect, useRef, useCallback } from 'react'; import { EpigramCommentProps } from '@/types/epigram.types'; +import useEpigramCommentsQuery from '@/hooks/useEpigramCommentsQueryHook'; import CommentItem from './CommentItem'; import NoComment from './NoComment'; function CommentList({ epigramId, currentUserId }: EpigramCommentProps) { - const { - data: comments, - isLoading, - error, - } = useEpigramCommentsQuery({ - id: epigramId, - limit: 3, - }); - - if (isLoading) return
댓글을 불러오는 중...
; - if (error) return
에러: {(error as Error).message}
; - const commentCount = comments?.list.length || 0; + const { data, fetchNextPage, hasNextPage, isFetchingNextPage, status } = useEpigramCommentsQuery(epigramId); + + const observerRef = useRef(null); + const lastCommentRef = useRef(null); + + const handleObserver = useCallback( + (entries: IntersectionObserverEntry[]) => { + const [target] = entries; + if (target.isIntersecting && hasNextPage) { + fetchNextPage(); + } + }, + [fetchNextPage, hasNextPage], + ); + + useEffect(() => { + const options = { + root: null, + rootMargin: '20px', + threshold: 1.0, + }; + + observerRef.current = new IntersectionObserver(handleObserver, options); + + if (lastCommentRef.current) { + observerRef.current.observe(lastCommentRef.current); + } + + return () => { + if (observerRef.current) { + observerRef.current.disconnect(); + } + }; + }, [handleObserver]); + + if (status === 'pending') return
댓글을 불러오는 중...
; + if (status === 'error') return
에러: 댓글을 불러오는데 실패했습니다.
; + + const allComments = data?.pages.flatMap((page) => page.list) || []; + const totalCount = data?.pages[0]?.totalCount || 0; return (
-

댓글({comments?.totalCount})

- {commentCount > 0 ? comments?.list.map((comment) => ) : } +

댓글({totalCount})

+ {allComments.length > 0 ? ( + <> + {allComments.map((comment) => ( + + ))} +
{isFetchingNextPage &&
더 많은 댓글을 불러오는 중...
}
+ + ) : ( + + )}
); } + export default CommentList; diff --git a/src/hooks/useEpigramCommentHook.ts b/src/hooks/useEpigramCommentHook.ts deleted file mode 100644 index 126695f5..00000000 --- a/src/hooks/useEpigramCommentHook.ts +++ /dev/null @@ -1,7 +0,0 @@ -import queries from '@/apis/queries'; -import { CommentRequestType } from '@/schema/comment'; -import { useQuery } from '@tanstack/react-query'; - -const useEpigramCommentsQuery = (request: CommentRequestType) => useQuery(queries.epigramComment.getComments(request)); - -export default useEpigramCommentsQuery; diff --git a/src/hooks/useEpigramCommentsQueryHook.ts b/src/hooks/useEpigramCommentsQueryHook.ts new file mode 100644 index 00000000..9c7a34a5 --- /dev/null +++ b/src/hooks/useEpigramCommentsQueryHook.ts @@ -0,0 +1,13 @@ +import { InfiniteData, useInfiniteQuery } from '@tanstack/react-query'; +import { CommentResponseType } from '@/schema/comment'; +import getEpigramComments from '@/apis/epigramComment'; + +const useEpigramCommentsQuery = (epigramId: number) => + useInfiniteQuery, [string, number], number | undefined>({ + queryKey: ['epigramComments', epigramId], + queryFn: ({ pageParam }) => getEpigramComments({ id: epigramId, limit: 3, cursor: pageParam }), + initialPageParam: undefined, + getNextPageParam: (lastPage) => lastPage.nextCursor ?? undefined, + }); + +export default useEpigramCommentsQuery; diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 076364a3..737859ce 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -1,4 +1,4 @@ const TOKEN = - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjIsInRlYW1JZCI6IjUtOSIsInNjb3BlIjoiYWNjZXNzIiwiaWF0IjoxNzIxMTg3NDgyLCJleHAiOjE3MjExODkyODIsImlzcyI6InNwLWVwaWdyYW0ifQ.Qpw2ByeGF-rkQ1wwJ2c7OtjyVXBevOsZhMeyuzZjosM'; + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjIsInRlYW1JZCI6IjUtOSIsInNjb3BlIjoiYWNjZXNzIiwiaWF0IjoxNzIxMjAwMTI0LCJleHAiOjE3MjEyMDE5MjQsImlzcyI6InNwLWVwaWdyYW0ifQ.BUQ4EAR04HMIg5YMAJI8Rd7aa6_GyAoZs89YL0TuCgg'; export default TOKEN;