[Tanstack Query] 7. 무한 스크롤과 더 보기

임승민·2025년 2월 16일
0

Tanstack Query

목록 보기
7/9
post-thumbnail

1. useInfiniteQuery

useInfiniteQuery는 목록 데이터를 점진적으로 불러와 ‘더 보기’ 또는 ‘무한 스크롤’을 구현할 때 사용되는 훅이다. useQuery와 유사하지만, 여러 페이지의 데이터를 효율적으로 관리할 수 있도록 추가 기능을 제공한다.

const {
  data,
  error,
  fetchNextPage,
  hasNextPage,
  isFetching,
  isFetchingNextPage,
  status,
} = useInfiniteQuery({
  queryKey: ['projects'],
  queryFn: fetchProjects,
  initialPageParam: 0,
  getNextPageParam: (lastPage, pages) => lastPage.nextCursor,
})

2. useInfiniteQuery의 추가 기능

데이터 구조 변화

data.pages: 불러온 모든 페이지 데이터를 포함하는 배열
data.pageParams: 각 페이지를 가져오는 데 사용된 매개변수를 포함하는 배열

추가 메서드

fetchNextPage: 다음 페이지 데이터를 불러오는 함수

fetchPreviousPage: 이전 페이지 데이터를 불러오는 함수

추가 옵션

initialPageParam: 초기 페이지 매개변수 (필수)

getNextPageParam: 다음 페이지를 불러올 수 있는 기준 정의

getPreviousPageParam: 이전 페이지를 불러올 수 있는 기준 정의

추가 상태값

hasNextPage: 다음 페이지가 존재하는지 여부 (getNextPageParam이 null/undefined가 아니면 true)
hasPreviousPage: 이전 페이지가 존재하는지 여부 (getPreviousPageParam이 null/undefined가 아니면 true)
isFetchingNextPage: 다음 페이지 데이터를 요청 중인지 여부
isFetchingPreviousPage: 이전 페이지 데이터를 요청 중인지 여부

3. ‘더 보기’ 예제

getNextPageParam

getNextPageParam을 보면 lastPage.nextPage값을 통해 다음 페이지가 있는지 설정한다.

{"items": [...], "nextPage": 3 } 서버에서 이런 형식의 데이터를 받았을 때의 상황이다.

만약 totalCount 정도만 받는다면 직접 계산을 해서 getNextPageParam에 넣으면 된다.

pageParam

useInfiniteQuery에서 queryFn의 인자로 pageParam를 자동으로 전달해준다.

<script setup>
import { useInfiniteQuery } from '@tanstack/vue-query'

const fetchPosts = async ({ pageParam = 0, limit = 10 }) => {
  const res = await fetch(`/api/posts?page=${pageParam}&limit=${limit}`)
  return res.json()
}

const {
  data,
  fetchNextPage,
  hasNextPage,
  isFetchingNextPage,
} = useInfiniteQuery({
  queryKey: ['posts'],
  queryFn: fetchPosts,
  initialPageParam: 1, // 초기 페이지
  getNextPageParam: (lastPage) => lastPage.nextPage, // 다음 페이지 번호 반환
})
</script>

<template>
  <div>
    <Post v-for="post in data?.pages.flatMap((group) => group.items)" :key="post.id" :post="post" />
    <button v-if="hasNextPage" @click="fetchNextPage" :disabled="isFetchingNextPage">
      {{ isFetchingNextPage ? '로딩 중...' : '더 보기' }}
    </button>
  </div>
</template>

0개의 댓글

관련 채용 정보