https://tanstack.com/query/latest/docs/react/guides/query-functions#queryfunctioncontext
1. 타입 지정
[PostList.tsx]
import { QueryFunctionContext, QueryKey, useInfiniteQuery } from '@tanstack/react-query';
import { DocumentData, QueryDocumentSnapshot } from 'firebase/firestore';
interface PostListProps {
queryKey: QueryKey;
queryFn: (
context: QueryFunctionContext<QueryKey, undefined | QueryDocumentSnapshot<DocumentData, DocumentData>>
) => Promise<QueryDocumentSnapshot<DocumentData, DocumentData>[]>;
}
2. 코드
[PostList.tsx]
function PostList({ queryKey, queryFn }: PostListProps) {
const { data: posts, fetchNextPage } = useInfiniteQuery({
queryKey,
queryFn,
initialPageParam: undefined as undefined | QueryDocumentSnapshot<DocumentData, DocumentData>,
getNextPageParam: (lastPage) => {
if (lastPage.length === 0) {
return undefined;
}
return lastPage[lastPage.length - 1];
},
select: (data) => {
return data.pages.flat().map((doc) => ({ id: doc.id, ...doc.data() } as PostType));
}
});
return (
▶ 외부에서 queryKey와 queryFn을 받아오고 타입은 위에서 interface로 정해놓음
▶ useInfiniteQuery를 사용하여 data와 fetchNextPage 값을 사용 (+ hasNextPage 추가 예정)
[initialPageParam]
★ 중요한 부분 : tanstack v5는 initialPageParam이 새로 생김.
=> initialPageParam에 지정한 타입이 getNextPageParam의 return 값의 타입임
=> 처음에 데이터를 보여주기 위해서 undefined가 필요하여 falsy value를 넣어줌
=> undefined 는 as 를 사용해서 강제주입하는데 undefined값 이거나~ QueryDocument~이거나 (파이어베이스)
[getNextPageParam]
▶ input인 lastPage와 output인 return값은 initialPageParam의 타입에 집중해야함.
[select]
▶ 옵션인데 데이터를 가공해서 사용가능
▶ select : (data) => Data 안에 pages / pageParams가 있는데 Data를 가르킴
▶ return data.pages => 위에서 말한 Data 안에 pages에 접근
▶ flat() 메소드 : 배열안 객체를 (이중배열) 를 단일배열로 만들기 위함
ex. arr =[1,2,[3,4]] => arr.flat(); // [1,2,3,4]
ex. arr.flat(2); // 2 = 없애는 대괄호 개수
ex. arr.flat(Infinity); // 모두 없애기
▶ map 메소드 : queryFn에서 사용한 데이터를 여기서 가공
[pageListApi.ts] > [queryFn = getAdminPostList]
import { QueryFunctionContext, QueryKey } from '@tanstack/react-query';
import { db } from '../shared/firebase';
import { DocumentData, QueryDocumentSnapshot, collection,getDocs,limit,query,startAfter,where} from 'firebase/firestore';
import { Category } from '../components/viewAll/ViewAllBody-jy-2';
//관리자
export const getAdminPostList = async (pageParam: undefined | QueryDocumentSnapshot<DocumentData, DocumentData>) => {
const q = pageParam
? query(collection(db, 'test'), where('role', '==', 'admin'), startAfter(pageParam), limit(4))
: query(collection(db, 'test'), where('role', '==', 'admin'), limit(4));
const querySnapShot = await getDocs(q);
return querySnapShot.docs;
// return querySnapShot.docs.map((doc) => ({
// id: doc.id,
// ...(doc.data() as Omit<PostType, 'id'>) //id 제외하고 나머지 필드를 PostType으로 변환
// }));
};
▶ 매개변수 pageParam의 타입은 initialPageParam과 동일
▶ pageParam이 값이 있으면, test 콜렉션의 role이 admin값만 4개 출력 ★startAfter(pageParam)
pageParam이 값이 없으면,(undefined) : 처음 4개의 게시물 보여주기
▶ 처음에, return 값을 여기서 가공해서 반환했는데, querySnapShot.docs로 반환 후
useInfiniteQuery의 Select 부분에서 가공
▶(파이어베이스) 스냅샷 처럼 사용 : 이것도 사용하려고 했었음
=> 그러다가 startAfter에 lastVisble이 아닌 pageParam으로 대체
const documentSnapshots = await getDocs(first);
// Get the last visible document
const lastVisible = documentSnapshots.docs[documentSnapshots.docs.length-1];
[PostList.tsx]
return (
<St.MainSubWrapper>
<St.ContentsWrapper>
<St.Contents>
{posts?.map((post) => (
<St.Content key={post.id}>
<p>{post.title}</p>
<p>{post.content}</p>
<p>{post.category}</p>
</St.Content>
))}
</St.Contents>
</St.ContentsWrapper>
<St.MoreContentWrapper>
<button onClick={() => fetchNextPage()}>더보기...</button>
</St.MoreContentWrapper>
</St.MainSubWrapper>
);
▶ 화면
▶ useInfiniteQuery에서 data: posts => 사용
▶ 버튼 클릭시 : () => fetchNextPage() 를 사용해서 queryFn 실행
3. useInfiniteQuery 실행 순서
1) queryFn 실행
2) getNextPageParam 실행 -> 리턴 값은 hook메모리에 저장
3) undefined에서 값이 들어오면서 hasNextPage:true로 변경
4) 그리고,, 이벤트리스너에 의해 fetchNextPage를 사용하면 => 다시 query 실행
5) 이때 getNextPageParam의 리턴값을 queryFn의 매개변수로 넘겨줌
끝.
'TIL :: Today I Learned' 카테고리의 다른 글
Styled-components: GlobalSytles.tsx에 공용 폰트 적용 (0) | 2024.01.12 |
---|---|
타입스크립트 + useInfiniteQuery : 정렬 기능 구현 (0) | 2024.01.11 |
리액트 : 게시글 '+더보기 버튼' 구현 : 시도(1) (0) | 2024.01.09 |
react-query 카테고리별 데이터 가져오기 (+ 반복되는 코드 줄이기) (2) | 2024.01.09 |
리액트 기술면접 대비 (1) (0) | 2024.01.05 |