※ 해당 섹션은 3버전 react query로 4버전과 다른 부분이 있을 수 있습니다.
useInfiniteQuery
tracks next queryex) API
{
"count": 37,
"next": "http: //swapi.dev/api/specie/?page=2",
"previous": null,
"results": [...]
}
useQuery
pages
arraypageParams
tracks the keys of queries that have been retrieved(pageParms는 검색되는 쿼리들의 키를 추적한다.)pageParams
is a paremeter passed to the queryFn (pageParam은 쿼리 함수에 전달되는 매개변수이다)pageParam
is maintained by React QueryuseInfiniteQuery
optionspageParam
lastPage
of data (specifically the next property)getNextPageParam
isFetching
and isFetchingNextPage
Component mounts → Fetch first page → getNextPageParam,
Update pageParam
→ hasNextPage
? →(yes) user scrolls / clicks button fetchNextPage
→ getNextPageParam
, Update pageParam
→(no) done!
import { useInfiniteQuery } from "@tanstack/react-query";
...
export function InfinitePeople() {
const { data, fetchNextPage, hasNextPage } = useInfiniteQuery(
["sw-people"], // queryKey
({ pageParam = initialUrl }) => fetchUrl(pageParam),
{
getNextPageParam: (lastPage) => lastPage.next || undefined, // (lastPage, allpages) 이나 2페이지 밖에 있지 않아 lastPage만 사용한다.
}
);
...
useInfiniteQuery
InfiniteScroll
component:data.pages[x].results
required - yes
type - function
description - A callback when more items are requested by the user. Receives a single parameter specifying the page to load e.g. function handleLoadMore(page) { / load more items here / } }
required - no
type - boolean
default - false
desdcrtiption - Whether there are more items to be loaded. Event listeners are removed if false.
ex)
...
return (
<InfiniteScroll loadMore={fetchNextPage} hasMore={hasNextPage}>
{data.pages.map((pageData) => {
return pageData.results.map((person) => {
return (
<Person
key={person.name}
name={person.name}
hairColor={person.hair_color}
eyeColor={person.eye_color}
></Person>
);
});
})}
</InfiniteScroll>
);
page의 타입을 지정해주기 위해 isLoading과 isError를 사용하여 나타내주어야한다.
...
const {
data,
fetchNextPage,
hasNextPage,
isLoading,
isError,
error,
} = useInfiniteQuery(
["sw-people"],
({ pageParam = initialUrl }) => fetchUrl(pageParam), // 초기 url로 시작해서 pageParam 값으로 fetchUrl을 실행한다.
{
getNextPageParam: (lastPage) => lastPage.next || undefined, // 이전페이지(lastPage) 의 다음프로퍼티를 불러와 새 페이지 데이터가 있을 때마다 PageParam에 지정해준다. SWAPI에서 지정한 대로 함수의 값이 null인 경우에는 undefined를 둔다. 함수 값이 지정되지 않으면 hasNextPage의 값도 거짓이 된다.
}
);
if (isLoading) return <div className="loading">Loading...</div>;
if (isError) return <div>Error! {error.toString()}</div>;
...
getNextPageParam: (lastPage, allPages) => unknown | undefined
When new data is received for this query, this function receives both the last page of the infinite list of data and the full array of all pages.(쿼리에서 새로운 데이터를 받아 올 때, 함수는 데이터의 infinite list의 마지막 페이지와 모든 페이지의 전체 배열 둘 다 받는다.)
It should return a single variable that will be passed as the last optional parameter to your query function.(쿼리 함수에서 마지막 선택적인 파라미터가 전달되는 단일 변수를 리턴해야한다.)
Return undefined
to indicate there is no next page available. (다음페이지가 이용가능한지 없는지를 나타내는 'undefined'를 반환해야한다.)
위처럼 진행하면 결과는 잘 나오지만 스크롤을 내릴 때 loading중이라는 문구가 나타나지 않아 isFetching을 사용해본다.
...
const {
data,
fetchNextPage,
hasNextPage,
isFetching,
isError,
error,
} = useInfiniteQuery(
["sw-people"],
({ pageParam = initialUrl }) => fetchUrl(pageParam),
{
getNextPageParam: (lastPage) => lastPage.next || undefined,
}
);
if (isFetching) return <div className="loading">Loading...</div>;
if (isError) return <div>Error! {error.toString()}</div>;
...
export function InfinitePeople() {
const { data, fetchNextPage, hasNextPage, isLoading, isFetching, isError, error } =
useInfiniteQuery(
["sw-people"],
({ pageParam = initialUrl }) => fetchUrl(pageParam),
{
getNextPageParam: (lastPage) => lastPage.next || undefined,
}
);
if (isLoading) return <div className="loading">Loading...</div>;
if (isError) return <div>Error! {error.toString()}</div>;
return (
<>
{isFetching && <div className="loading">Loading...</div>} // 조건부 렌더링을 사용하여 isFetching이 진행되면 Loading이라는 문구가 오른쪽 상단에 나타나게 설정해준다.
<InfiniteScroll loadMore={fetchNextPage} hasMore={hasNextPage}>
{data.pages.map((pageData) => {
return pageData.results.map((person) => {
return (
<Person
key={person.name}
name={person.name}
hairColor={person.hair_color}
eyeColor={person.eye_color}
/>
);
});
})}
</InfiniteScroll>
</>
);
}
<InfiniteScroll loadMore={fetchNextPage} hasMore={hasNextPage}>
loadMore의 fetchNextPage는 useInfiniteQuery에 영향을 받아 어떤 쿼리 함수든 pageParam 값을 쓰게 되고 pageParam값은 데이터가 추가되면 갱신됩니다.
hasMore 함수는 InfiniteScroll 컴포넌트가 계속 데이터를 불러올지를 결정하는 역할을 해요. 이 함수는 hasNextPage 프로퍼티의 영향을 받고 pageParam이 정의되지 않아 거짓이 되는 경우도 lastPage.next 를 통해 다음 프로퍼티가 없거나 프로퍼티가 거짓인 경우도 정의했습니다.
useQuery와 useInfiniteQuery의 함수 결과는 다릅니다.
useQuery는 쿼리 함수의 결과를 그대로 출력합니다.
useInfiniteQuery 가 반환하는 데이터에 든 프로퍼티 중 사용하는 건 페이지 프로퍼티고 여기에는 pageParam이 실행될 때마다 필요한 데이터 배열이 들어있습니다.
pageParam
for next page to be fetched (pageParam 배열은 가져와야 할 다음 페이지를 나타내는데getNextPageParam
option (getNextPageParam 을 통해 관리되며)lastPage
, or allPages
(두 가지 매개변수를 사용합니다.)hasNextPage
(pageParam은 또 hasNextPage 값을 제어하는데)pageParam
is undefined
(이 불리언 값은 pageParam이 정의되어 있으면 참, 정의되지 않았으면 거짓을 반환해서 더 불러올 데이터가 있는지를 확인할 수 있습니다.)fetchNextPage
(fetchNextPage는 컴포넌트의 영향을 받기 때문에 컴포넌트가 데이터를 불러와야 할 때를 결정하고 hasNextPage 프로퍼티로 데이터를 그만 가져오게 할 수 있습니다.)hasNextPage
value to determine when to stopreference
https://www.udemy.com/course/learn-react-query
https://tanstack.com/query/v4/docs/installation?from=reactQueryV3&original=https://react-query-v3.tanstack.com/installation
https://tanstack.com/query/v4/docs/quick-start?from=reactQueryV3&original=https://react-query-v3.tanstack.com/quick-start
https://tanstack.com/query/v4/docs/devtools?from=reactQueryV3&original=https://react-query-v3.tanstack.com/devtools
https://tanstack.com/query/v4/docs/reference/useInfiniteQuery