이전 토이 프로젝트에서는 react-router 와 함께 사용하여
loader 를 이용하여 페이지가 열리기 전, 사전에 데이터를 가져오는 방법을 사용했었지만
순수하게 TanStack Query 를 사용하여 사전에 데이터를 가져오는 방법을 찾아보았습니다.
prefetchQuery & prefetchInfiniteQuery
TanStack | High Quality Open-Source Software for Web Developers
Headless, type-safe, powerful utilities for complex workflows like Data Management, Data Visualization, Charts, Tables, and UI Components.
tanstack.com
- staleTime을 사용하여 캐시의 기존 데이터가 최신인지 또는 다시 가져와야 하는지 여부를 결정합니다.
- staleTime을 무시하고 대신 캐시에서 데이터를 사용할 수 있는 경우 항상 데이터를 반환하려면 ensureQueryData 함수를 사용하면 됩니다.
- 이러한 함수는 Promise<void>를 반환하므로 쿼리 데이터를 반환하지 않습니다.
이 기능이 필요한 경우 대신 fetchQuery/fetchInfiniteQuery를 사용하세요. - 프리페치 함수는 일반적으로 사용 쿼리에서 다시 가져오기를 시도하기 때문에 오류가 발생하지 않습니다.
오류를 잡아야 하는 경우 대신 fetchQuery/fetchInfiniteQuery를 사용하세요.
prefetchQuery와 prefetchInfiniteQuery 의 차이는 무한 스크롤 의 유무라고 생각하면 됩니다.
prefetchQuery: 상세 페이지 데이터, 단일 목록 등
prefetchInfiniteQuery: 소셜 미디어 피드, 댓글 목록, 제품 목록 등 무한 스크롤이 필요한 경우
여기서는 prefetchQuery만 살펴보도록 하겠습니다.
예를 들어 prefetchQuery 를 사용하는 페이징 처리가 있다고 가정해 봅시다.
import { useState, useEffect } from "react";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { fetchPosts } from "./api";
const maxPostPage = 10;
export function Posts() {
const [currentPage, setCurrentPage] = useState(1);
const [selectedPost, setSelectedPost] = useState(null);
const queryClient = useQueryClient();
// 다음 페이지 정보를 미리 받아 cache 에 저장
useEffect(() => {
if(currentPage < maxPostPage) {
const nextPage = currentPage + 1;
queryClient.prefetchQuery({
queryKey: ["posts", nextPage],
queryFn: () => fetchPosts(nextPage),
})
}
}, [currentPage, queryClient])
// 기존 list 불러오는 useQuery
const { data, isLoading, isError, error } = useQuery({
queryKey: ["posts", currentPage],
queryFn: () => fetchPosts(currentPage),
staleTime: 1000 * 2,
});
if(isLoading) return <h2>Loading...</h2>
if(isError) return <p>{error.toString()}</p>
return (
);
}
- useQueryClient 임포트
- const queryClient = useQueryClient(); 로 변수할당
- useEffect 사용
- queryClient.prefetchQuery 를 사용하여 queryKey, queryFn 적용
queryKey 에는 nextPage 도 함께 넣어주고
queryFn에는 () => fetchPosts(nextPage) 로 다음 페이지 번호도 파라미터로 함께 넘겨줌 - 종속성 배열에는 currentPage, queryClient 추가
- 현재 페이지가 maxPostPage 보다 작을 때만 실행되도록 if 문 추가
를 해주면
이렇게 미리 다음 페이지를 받아와 사용자 경험을 개선할 수 있으며,
물론 staleTime 을 늘려주면 api call 중복을 줄여줄 수 있습니다.
// 다음 페이지 정보를 미리 받아 cache 에 저장
useEffect(() => {
if(currentPage < maxPostPage) {
const nextPage = currentPage + 1;
queryClient.prefetchQuery({
queryKey: ["posts", nextPage],
queryFn: () => fetchPosts(nextPage),
// staleTime: 1000 * 5, // 5초
})
}
}, [currentPage, queryClient])
// 기존 list 불러오는 useQuery
const { data, isLoading, isError, error } = useQuery({
queryKey: ["posts", currentPage],
queryFn: () => fetchPosts(currentPage),
staleTime: 1000 * 2, // 2초
});
위의 예시 코드처럼 prefetchQuery 의 staleTime 은, useQuery 의 2초에 맞춰서 stale 처리가 된 후, 데이터를
새로 불러오므로 의미가 없는 코드가 됩니다.