Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

무한스크롤 관련 정리 #48

Open
ruehan opened this issue Oct 30, 2024 · 1 comment
Open

무한스크롤 관련 정리 #48

ruehan opened this issue Oct 30, 2024 · 1 comment
Assignees
Labels

Comments

@ruehan
Copy link
Collaborator

ruehan commented Oct 30, 2024

커뮤니티를 기준으로 무한스크롤 예시를 만들어봤습니다.
실제 코드와 다른 부분이 있으니 참고용으로 사용하시면 좋을 듯 합니다.

// 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>
  );
};

@zelkovaria @kod0751

@ruehan ruehan self-assigned this Oct 30, 2024
@zelkovaria
Copy link
Collaborator

useEffect 부분은 좀 더 비교해서 학습해볼게용 ㅎㅎ 감사합니당!

@zelkovaria zelkovaria added the 📝 docs docs label Nov 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants