[2024-01-28] 개인 프로젝트 회고
1. useInfiniteQuery 사용하기!
TanStack Query에서 사용할 수 있는 useInfiniteQuery가 있는데
이 훅은 무한 스크롤이나 load more(더 보기)과 같이
특정 조건에서 데이터를 추가적으로 받아오는 기능을 구현할 때 사용하면 유용하다.
useInfiniteQuery 반환값
const {
fetchNextPage,
fetchPreviousPage,
hasNextPage,
hasPreviousPage,
isFetchingNextPage,
isFetchingPreviousPage,
...result
} = useInfiniteQuery({
queryKey,
queryFn: ({ pageParam }) => fetchPage(pageParam),
initialPageParam: 1,
...options,
getNextPageParam: (lastPage, allPages, lastPageParam, allPageParams) =>
lastPage.nextCursor,
getPreviousPageParam: (firstPage, allPages, firstPageParam, allPageParams) =>
firstPage.prevCursor,
})
isFetchingNextPage, isFetchingPreviousPage, fetchNextPage, fetchPreviousPage, hasNextPage 등이 추가적으로 있다.
- data.pages: 모든 페이지 데이터를 포함하는 배열이다.
- data.pageParams: 모든 페이지 매개변수를 포함하는 배열이다.
- fetchNextPage: 다음 페이지를 fetch 할 수 있다.
- fetchPreviousPage: 이전 페이지를 fetch 할 수 있다.
- isFetchingNextPage: fetchNextPage 메서드가 다음 페이지를 가져오는 동안 true이다.
- isFetchingPreviousPage: fetchPreviousPage 메서드가 이전 페이지를 가져오는 동안 true이다.
- hasNextPage: 가져올 수 있는 다음 페이지가 있을 경우 true이다.
- hasPreviousPage: 가져올 수 있는 이전 페이지가 있을 경우 true이다.
주요 옵션
initialPageParam: TPageParam
- initialPageParam을 이용해서 첫 페이지를 가져올 때 사용할 기본 페이지 매개변수이다. 필수값이다.
getNextPageParam: (lastPage, allPages, lastPageParam, allPageParams) => TPageParam | undefined | null
- getNextPageParam 을 이용해서 페이지를 증가시킬 수 있다. 필수값이다.
- getNextPageParam의 첫 번째 인자 lastPage는 fetch 해온 가장 최근에 가져온 페이지 목록이다.
- 두 번째 인자 allPages는 현재까지 가져온 모든 페이지 데이터이다.
- 세 번째 인자 firstPageParam 는 첫 번째 페이지의 매개변수이다.
- 네 번째 인자 allPageParams 는 모든 페이지의 매개변수이다.
사용 가능한 다음 페이지가 없음을 표시하려면 undefined 또는 null을 반환하면 된다.
getPreviousPageParam도 존재하며, getNextPageParam와 반대의 속성을 갖고 있다.
maxPages: number | undefined
- infinite 쿼리에 저장 할 최대 페이지 수이다.
- 최대 페이지 수에 도달했는데 새 페이지를 가져오면 지정된 방향(next, previous)에 따라 페이지 배열에서 첫 번째 페이지 또는 마지막 페이지가 제거된다.
- 0 또는 undefined라면 페이지 수는 무제한이다.
일단 실제 예제를 보면서 이해해보자
import { useInfiniteQuery } from '@tanstack/react-query'
import { getHerbList } from '~/api/herbList'
import { HerbList, HerbInfos } from '~/types/herbList'
const useGetHerbList = (pageNo = 1, numOfRows = 10) => {
const { data, hasNextPage, isFetching, isFetchingNextPage, fetchNextPage } =
useInfiniteQuery<HerbList>({
queryKey: ['herb', { pageNo, numOfRows }],
queryFn: ({ pageParam = pageNo }) =>
getHerbList({ pageNo: pageParam as number, numOfRows }),
initialPageParam: 1,
getNextPageParam: (lastPage, allPages) => {
if (lastPage.length < numOfRows) return undefined
return allPages.length + 1
}
})
const isHerb = {
isHerb: true
}
const result = data?.pages.flat().map((d: HerbInfos) => ({ ...d, ...isHerb }))
return {
herbList: result || [],
isFetching,
isFetchingNextPage,
hasNextPage,
fetchNextPage
}
}
export default useGetHerbList
console.log(allPages를 했을 때 나오는 로그다
이를통해 페이지 단위로 데이터를 갖고온다.
그래서 getNextPageParam은 allPages의 length+ 1한 값을 반환해서 pageParams에 저장한다.
getNextPageParam: (lastPage, allPages, allPageParams) => {
if (lastPage.length < numOfRows) return undefined;
return (allPageParams as number) + 1
}
그래서 allPageParams를 사용해도 된다.
즉, getNextPageParam의 반환 값이 pageParams로 들어간다.
maxPage는 뭐야??
[React] react-query v5 변경점 알아보기 (4) - useInfiniteQuery 기능 변경
안녕하세요. J4J입니다. 이번 포스팅은 react-query v5 변경점 알아보기 네 번째인 useInfiniteQuery 기능 변경에 대해 적어보는 시간을 가져보려고 합니다. 이전 글 [React] react-query v5 변경점 알아보기 (1) -
jforj.tistory.com
2. intersection Observer로 무한스크롤 구현하기!
1. useInfiniteScroll 커스텀 훅 만들기!
import { useEffect, useRef } from 'react'
const useInfiniteScroll = <T extends Element>(
callback: () => void,
options?: IntersectionObserverInit
) => {
const ref = useRef<T>(null) //감시할 요소를 저장할 ref 생성
// IntersectionObserver를 생성, callback 함수는 감시 대상이 화면에 나타날 때 호출된다.
useEffect(() => {
const observer = new IntersectionObserver(
entries => entries.forEach(entry => entry.isIntersecting && callback()),
options || { threshold: 0.5 }
)
//ref에서 현재 요소를 가져온다.
const target = ref && ref.current
// ref가 없으면 아무 작업도 하지 않고 종료 ref가 null이면 감시할 필요가없으니까
if (!target) return
// IntersectionObserver를 사용해 감시 대상을 감시
observer.observe(target)
// 컴포넌트가 언마운트되면 IntersectionObserver에서 감시를 해제
return () => observer.unobserve(target)
}, [callback, options])
return { ref }
}
export default useInfiniteScroll
2. 만든 커스텀 훅을 사용!
import useInfiniteScroll from '~/hooks/useInfiniteScroll'
const CardListPage = () => {
...
const { ref } = useInfiniteScroll<HTMLDivElement>(refetch)
return (
...
<div ref={ref}></div>
)
}
export default CardListPage