Skip to content

Commit

Permalink
feat: 댓글 무한 스크롤 기능 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
seongminn committed Nov 27, 2023
1 parent 4b7dafa commit a8c0351
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 6 deletions.
4 changes: 2 additions & 2 deletions src/app/match/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ export default function Match({ params }: { params: { id: string } }) {
scrollToBottom={scrollToBottom}
{...data}
/>
<CommentList commentList={comments} />
<div ref={scrollRef}></div>
<CommentList.SocketList commentList={comments} />
<li ref={scrollRef}></li>
</ul>
<CommentForm
matchId={params.id}
Expand Down
34 changes: 30 additions & 4 deletions src/components/match/CommentList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,35 @@

import { useEffect } from 'react';

import useInfiniteObserver from '@/hooks/useInfiniteObserver';
import { MatchCommentType } from '@/types/match';

import CommentItem from '../CommentItem';

type CommentListProps = {
commentList: MatchCommentType[];
hasNextPage?: boolean;
fetchNextPage?: () => void;
isFetching?: boolean;
scrollToBottom?: () => void;
hasNextPage: boolean;
fetchNextPage: () => void;
isFetching: boolean;
scrollToBottom: () => void;
};

export default function CommentList({
commentList,
fetchNextPage,
hasNextPage,
isFetching,
scrollToBottom,
}: CommentListProps) {
const { ref } = useInfiniteObserver<HTMLDivElement>(
async (entry, observer) => {
observer.unobserve(entry.target);
if (hasNextPage && !isFetching) {
fetchNextPage();
}
},
);

useEffect(() => {
if (!scrollToBottom) return;

Expand All @@ -26,9 +39,22 @@ export default function CommentList({

return (
<>
<div ref={ref}></div>
{commentList.map(comment => (
<CommentItem {...comment} key={comment.commentId} order={1} />
))}
</>
);
}

CommentList.SocketList = function SocketList({
commentList,
}: Pick<CommentListProps, 'commentList'>) {
return (
<>
{commentList.map(comment => (
<CommentItem {...comment} key={comment.commentId} order={1} />
))}
</>
);
};
33 changes: 33 additions & 0 deletions src/hooks/useInfiniteObserver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { useCallback, useEffect, useRef } from 'react';

type IntersectHandler = (
entry: IntersectionObserverEntry,
observer: IntersectionObserver,
) => void;

export default function useIntersect<T extends HTMLElement>(
onIntersect: IntersectHandler,
options?: IntersectionObserverInit,
) {
const ref = useRef<T | null>(null);
const callback = useCallback(
(entries: IntersectionObserverEntry[], observer: IntersectionObserver) => {
entries.forEach(entry => {
if (entry.isIntersecting) onIntersect(entry, observer);
});
},
[onIntersect],
);

useEffect(() => {
if (!ref.current) return;

const observer = new IntersectionObserver(callback, options);

observer.observe(ref.current);

return () => observer.disconnect();
}, [ref, options, callback]);

return { ref };
}

0 comments on commit a8c0351

Please sign in to comment.