작성
·
144
0
[username]/status/[id] 페이지에 접근했을 때
해당 게시글의 답글을 리액트 쿼리의 인피니트 스크롤을 통해 가져오는데
제로초님이 직접 배포하신 z.nordbird.com도 그렇고
제가 강의를 통해 만들고 있는 페이지에 인피니트 스크롤을 적용해봐도
리액트 쿼리를 통해 가져오는 데이터가 계속 중복이 되는데
(cursor 값이 증가하면서 다음 답글을 가지고 오지 못하고 어떤 cursor를 기준으로 이보다 작은 값을 가지는 답글만 fetching 됨)
코드상의 오류는 아니고 백엔드 설계가 그렇게 되어 있는 거죠?
답글 무한 스크롤 결과(pageParam이 96을 넘어가지 못함)
답글 인피니트 스크롤 부분 코드는 배포된 페이지 깃에 올라온 내용과 동일합니다.
답변 2
0
답글이 뭔가요?? comments 말씀하시는 건가요?
cursor가 0일 때의 첫 데이터 로딩이 중요한데요. 여기의 데이터 순서가 내림차순인지 오름차순인지 확인이 필요합니다.
다음 게시글을 불러오는 getNextPageParams의 번호를 수정하면 됩니다. 방금 받은 리스트에서 가장 작은 숫자가 되도록요.
예를 들어 46~55 게시글을 불러왔다면 getNextPageParams는 46이어야 합니다.
아래와 같이 수정을 해봤습니다
"use client";
import { InfiniteData, useInfiniteQuery, useQuery, useQueryClient } from "@tanstack/react-query";
import getPostComments from "../_lib/getPostComments";
import { Post as IPost } from "@/model/Post";
import Comment from "./Comment";
import Comments from "@/app/(afterLogin)/_component/Comments";
import CommentForm from "../../../_component/CommentForm";
import { Fragment, useEffect } from "react";
import { useInView } from "react-intersection-observer";
type Props = {
params: { username: string; id: string };
};
export default function PostComments({ params }: Props) {
const queryClient = useQueryClient();
const postData = queryClient.getQueryData<IPost>(["post", params.id]);
const { data, fetchNextPage, hasNextPage, isFetching } = useInfiniteQuery<IPost[], Object, InfiniteData<IPost[]>, [_1: string, _2: string, _3: string], number>({
queryKey: ["posts", "comments", params.id],
queryFn: getPostComments,
initialPageParam: 0,
getNextPageParam: (lastPage) => lastPage.at(0)?.postId,
// getNextPageParam: (lastPage) => lastPage.at(-1)?.postId,
// enabled: !!postData,
});
const { ref, inView } = useInView({
threshold: 0,
delay: 0,
});
useEffect(() => {
if (inView) {
!isFetching && hasNextPage && fetchNextPage();
}
}, [inView, isFetching, hasNextPage, fetchNextPage]);
if (!data) return null;
if (postData) {
return (
<>
{data?.pages.map((page, i) => (
<Fragment key={i}>
{page.map((post) => (
<Comment key={post.postId} post={post} />
))}
</Fragment>
))}
<div ref={ref} style={{ height: 50 }} />
</>
);
}
return null;
}
리액트 쿼리 dev tool을 봤을 때는 cursor가 이전 요청의 첫 번째 postId가 잘 넘어간 것으로 보입니다.
하지만 이렇게 되면 두 번째 쿼리 요청이 빈 배열이 나오면서 hasNextPage가 false가 되어 더 이상 데이터를 가지고 오지 않는 것 같습니다.
돌아오는 리액트 쿼리의 결과를 봤을 때,
cursor가 0으로 갈 때는 postId가 0이상인 comments들이 잘 돌아옵니다만,
0이 아니었을 때는 cursor의 값보다 작은 postId를 가지는 comments들을 오름차순 정렬해서 내보내는 것 같습니다.
cursor가 0으로 갈 때는 postId가 0이상인 comments들이 잘 돌아옵니다만,
0이 아니었을 때는 cursor의 값보다 작은 postId를 가지는 comments들을 오름차순 정렬해서 내보내는 것 같습니다
네 이 동작이 맞는데요. 현재 오름차순 정렬해서 내보내진다는 말씀이신가요? 아니면 빈 배열이라는 말씀이신가요? 46-55 게시글을 가져온 뒤 getNextPageParam이 46이 되어 36-45를 가져오는 그런 방식으로 동작하는 것입니다.
pages[i]에 comments가 담겨올 때 comments의 모든 postId는 오름차순 정렬되어 있습니다.
46-55 게시글을 가져온 뒤 getNextPageParam이 46이 되어 36-45를 가져오는 그런 방식으로 동작하는 것입니다.
저도 위와 같이 이해를 했습니다만, 아래와 같이 첫 번째 postId를 다음 cursor로 설정한다면
getNextPageParam: (lastPage) => lastPage.at(0)?.postId,
pages[0]에 담긴 comments의 postId가 46~55인 상황으로 가정한다면, postId가 46인 comments가 어떤 게시글의 첫 comment 일 텐데,
getNextPageParam이 46이 된다면, 해당 게시글에 담긴 답글 중에는 postId가 46보다 작은 comments는 없기 때문에 빈 배열이 돌아온다는 뜻이었습니다.
pages[0]은 46~54 -> 다음 cursor는 46,
pages[1] = []
아래와 같이 cursor가 설정되면
getNextPageParam: (lastPage) => lastPage.at(-1)?.postId,
pages[0]의 postId가 46~55라고 가정 -> 다음 cursor는 55.
pages[1]은 46 ~ 54 -> 다음 cursor는 54
pages[2]는 46 ~ 53 -> 다음 cursor는 53
...
pages[8]은 46 ~ 47 -> 다음 cursor = 47
pages[9] 46~46 -> 다음 cursor = 46
pages[10] = []
이해가 잘 안 됩니다.
예를 들어 46-55 게시글을 가져올 때 cursor가 46이 되고,
46 미만의 아이디가 없다면 당연히 다음 답글은 [] 빈 배열이 되는 게 맞습니다.
애초에 처음에 커서가 0일 때 가장 최신의 게시글 46-55를 가져왔으므로 더 가져올 게 없죠. 55가 가장 최신인 것이고, 46미만의 아이디는 없다고 하셨으니까요.
네 말씀 하신 부분 동작까지 저도 이해했습니다.
다만, 어떤 게시글의 comment가 46~55까지만 있으면 괜찮은데
56, 57, 58 등등도 있을 때 현재는 이 comment들은 불러와지지 않고
46~55 데이터만 불러와져서 질문드렸습니다.
네 맞습니다.
최신 comment가 안 불러와져서 질문드렸습니다.
제가 너무 돌려돌려 말씀드린 것 같네요. 상세하게 설명 드린다는게 오히려 요지 파악을 힘들게 만든 것 같네요 😭
0
안녕하세요, 인프런 AI 인턴입니다.
김지환님의 질문에 대해, 인피니트 스크롤 구현시 중복 데이터 문제와 cursor 값을 활용한 데이터 페칭 문제를 해결하는 방법에 대해 다루는 기존 답변을 찾을 수 있습니다. 다만, 직접적인 답변이나 코드 수정 제안이 포함된 자세한 답변을 제공하지는 못하고, 유사한 상황에서의 일반적인 해결책과 관련된 논의를 찾았습니다.
무한 스크롤과 관련하여 중복 데이터 문제나 cursor 기반 페이징 처리에 문제가 생기는 경우, 일반적으로 페이지나 cursor 파라미터의 관리, 백엔드의 데이터 반환 로직 검토, 프론트엔드에서의 데이터 처리 방식 등을 점검해야 합니다. 예를 들어, cursor 값이 잘못 계산되거나, 백엔드에서 동일한 데이터 세트를 반환하도록 구성된 경우와 같이 여러 가능성이 있습니다.
이 문제는 여러 원인에 의해 발생할 수 있으며, 백엔드의 데이터 처리 방식, 리액트 쿼리의 활용 방식 등 다양한 요소의 검토가 필요합니다.
이와 유사한 문제를 다룬 기존 답변을 참고하는 것이 도움이 될 수 있지만, 귀하의 경우에 해당하는 구체적인 해결책을 제공하는 것은 어렵습니다. 그럼에도 불구하고, 인피니트 스크롤 구현시 발생할 수 있는 일반적인 문제와 해결 방식에 대해 이해하는데 도움이 되는 링크는 아래와 같습니다.
자세한 문제 해결 방안은 각 경우의 상황에 따라 다를 수 있으며, 백엔드 상의 데이터 처리 로직과 프론트엔드에서의 데이터 호출 및 처리 과정에서의 상세 구현을 검토하는 것이 중요합니다.
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.
네 위 글의 답글은 comments(api/posts/{id}/comments) 맞습니다.
아래 사진은 제가 만들고 있는 부분입니다.
아래의 예시에서
cursor가 0일 때 뿐 아니라 모든 cursor에서 pages[i][j]의 데이터 순서는 오름차순입니다.
이후 스크롤 발생 후 다음 데이터 fetch 결과에서
'안녕하세요?' 글에 대한 comment가
'댓글 달기 10' 이후에도 '댓글 달기 11'과 '댓글 달기 12'가 있음에도
첫 번째 데이터와 중복된 데이터가 두 번째 fetch에도 오는 것을 알 수 있습니다.
z.nordbird.com도 동일하게 중복된 comment들이 fetching되는 현상을 보입니다.
왜 그런지는 모르겠으나
처음에 10개의 데이터를 가져오고
두 번째에 9개
세 번째에 8개 -> 7개 -> ... ->
마지막으로 fetching된 데이터는 pages[0][0]와 동일한 데이터입니다.
때문에 새로운 comment가 아닌, 중복된 comment가 화면에 보여지게 됩니다.