useInfiniteQuery + Firestore
React Query에서 나름 강력크한 기능 중 하나가 infiniteQuery지.
Flatlist로 무한 스크롤 같은 거 구현할 때 데이터를 계속 읽어와야 하잖아. 그럴 때 useInfiniteQuery를 사용해서 연속적으로 데이터를 읽어와. 무한 스크롤 안들어간 앱 찾기가 힘드니까 거의 필수라고 볼 수 있지. Query할 DB는 다른 건 열심히 안해봤고 Firestore는 지금 사용중인데 잘 돌아가네.
useInfiniteQuery 원래 문서는 아래 링크에 있으니까 참고해
https://react-query.tanstack.com/reference/useInfiniteQuery
그럼 먼저 useInfiniteQuery 사용법을 한 번 보자구. useInfiniteQuery 사용하기 위해서는 1. Query 변수, 2. Query 함수, 3. 다음 페이지 번호 가져오는 함수 이렇게 최소 3가지가 필요해. 아래 코드를 대강 살펴보자고~
const cardQuery = useInfiniteQuery(
["pokemonCard"], //1. 쿼리 변수!!!!!!!!!
async ({queryKey, pageParam}) => { //2. 쿼리 함수!!!!!!!!!
return pageParam ? //PageParam 이 있다면
firestore()
.collection("pokemonCard") // pokemonCard 컬렉션에서
.orderBy("createdAt","desc") // createdAt 내림차순으로 정렬하고
.startAfter(pageParam) //pageParam 부터 가져오는데
.limit(25) // 25개만 가져오도록 제한하고
.get()
.then((querySnapshot) => querySnapshot)
: firestore() //pageParam이 없으면 첫 Query!
.collection("pokemenCard")
.orderBy("createdAt","desc") // createdAt 내림차순으로 정렬하고
.limit(25) // 25개만 가져오도록 제한하고
.get()
.then((querySnapshot) => querySnapshot)
},
{
getNextPageParam: (querySnapshot) => { //3. 다음 페이지 번호 가져오는 함수!!!!!!!!!
if (querySnapshot.size < 25) return null;
//가져온 스냅샷 갯수가 25개 보다 작다는 의미는 끝까지 다 읽은거라 다음 페이지가 없다(null) 반환!
else return querySnapshot.docs[querySnapshot.docs.length - 1];
//아니면 가져온 문서의 마지막을 NextPage 파라미터로 돌려줌.
},
}
);
간단히 설명하자면 useInfiniteQuery는 getNextPageParam로 다음에 가져올 페이지 파라미터를 Query 함수로 전달해. 페이지 파라미터를 전달받은 Query 함수가 적절하게 데이터를 읽어오면 끝! 여기서 주의할 건 Query 함수에 전달할 페이지 파라미터만 신경써주는 것임.
https://firebase.google.com/docs/firestore/query-data/query-cursors?hl=ko#web-version-9_3
Firestore는 startAfter(), startAt(), endBefore(), endAt() 요런 걸로 pagination(페이지화)하는데 얘네들은 documentSnapshot을 cursor(커서)로 사용해. startAfter(documentSnapshot) 하면 documentSnapshot 다음 문서에 커서를 두고 읽어올 수 있어. 그래서 getNextPageParam에서 뭉탱이로 읽어온 querySnapshot(문서 뭉탱이)의 마지막 문서를 파라미터로 전달하는 거지. 이건 DB 종류나 사용하는 API에 따라서 달라지니까 맞춰서 하면 돼.
그리고 다음 페이지 불러올 땐 아래 코드처럼 간단하게 fetchNextPage() 메서드 사용하면 되고
const fetchMore = () => {
if (cardQuery.hasNextPage) {
cardQuery.fetchNextPage();
} else {
if (__DEV__) console.log("no next page");
}
};
그리고 Flatlist에서는 아래 코드처럼 onEndReached 에 다음 페이지 읽어오는 함수 물려주면 되고
<FlatList
...
onEndReached={loadMore}
...
/>
이게 한번 익숙해지면 쉬운데 그 전까지는 조금 헤깔리는 게 있어. React Query 문서도 뭐랄까 조금 불친절하고 그래서 ㅎㅎㅎ 내가 맘속 깊이 영어를 배척하는 것일지도 ㅋㅋㅋㅋㅋ
React native하면서 Flatlist + useInfiniteQuery 는 거의 뭐 필수니까 꼭 익숙해지길 바래~~