-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Labels
📝 docsdocsdocs
Description
커뮤니티를 기준으로 무한스크롤 예시를 만들어봤습니다.
실제 코드와 다른 부분이 있으니 참고용으로 사용하시면 좋을 듯 합니다.
// types
export interface UserInfo {
nickname: string;
profile_image: string;
}
export interface Post {
id: number;
user_id: number;
emotion_type: string;
content: string;
ai_content: string;
created_at: string;
is_shared: boolean;
is_solved: boolean;
like_count: number;
comment_count: number;
user_info: UserInfo;
}
export type SortOption = 'latest' | 'oldest' | 'comments' | 'likes';// api/posts.ts
import axios from 'axios';
import { Post, SortOption } from '../types/post';
const BASE_URL = 'https://calmiary-be.org';
interface FetchPostsParams {
pageParam?: number;
sortBy?: SortOption;
}
export const fetchPosts = async ({ pageParam = 1, sortBy = 'latest' }: FetchPostsParams) => {
const response = await axios.get<Post[]>(`${BASE_URL}/posts`, {
params: {
page: pageParam,
limit: 3,
sort_by: sortBy,
},
});
return response.data;
};// components/PostList.tsx
import React from 'react';
import { useInfiniteQuery } from '@tanstack/react-query';
import { useInView } from 'react-intersection-observer';
import { Post, SortOption } from '../types/post';
import { fetchPosts } from '../api/posts';
interface PostListProps {
sortBy: SortOption;
}
export const PostList = ({ sortBy } : PostListProps) => {
// ref: 관찰할 요소에 붙일 참조
// inView: 해당 요소가 뷰포트에 보이는지 여부
const { ref, inView } = useInView();
const {
data, // 페이지별 데이터를 포함하는 객체
isLoading, // 로딩 상태
isError, // 에러 발생 여부
hasNextPage, // 다음 페이지 존재 여부
fetchNextPage, // 다음 페이지 데이터를 불러오는 함수
isFetchingNextPage, // 다음 페이지 로딩 상태
} = useInfiniteQuery({
queryKey: ['posts', sortBy], // queryKey는 적절하게 변경
// 실제 데이터를 가져오는 함수
queryFn: ({ pageParam = 1 }) => fetchPosts({ pageParam, sortBy }),
// 다음 페이지 파라미터를 결정하는 함수
getNextPageParam: (lastPage, allPages) => {
// 마지막 페이지가 3개의 항목을 가지고 있으면 다음 페이지가 있다고 판단 가능
return lastPage.length === 3 ? allPages.length + 1 : undefined;
},
// 초기 페이지
initialPageParam: 1,
});
useEffect(() => {
// 관찰 대상이 화면에 보이고 다음 페이지가 있다면
if (inView && hasNextPage) {
fetchNextPage(); // 다음 페이지 로드
}
}, [inView, hasNextPage, fetchNextPage]);
if (isLoading) return <div>Loading...</div>;
if (isError) return <div>Error loading posts</div>;
return (
<div className="post-list">
{data.pages.map((group, i) => (
<Fragment key={i}>
{group.map((post: Post) => (
<div key={post.id} className="post-card">
<h3>{post.content}</h3>
<div className="post-meta">
<span>좋아요: {post.like_count}</span>
<span>댓글: {post.comment_count}</span>
</div>
<div className="user-info">
<img src={post.user_info.profile_image} alt="Profile" />
<span>{post.user_info.nickname}</span>
</div>
</div>
))}
</Fragment>
))}
// 여기가 intersection observer에서 관찰하는 부분..!
<div ref={ref} style={{ height: '20px' }}>
{isFetchingNextPage && <div>Loading more...</div>}
</div>
</div>
);
};minjeongss, kod0751 and zelkovaria
Metadata
Metadata
Assignees
Labels
📝 docsdocsdocs