본문 바로가기

TanStack Query

[TanStack Query / React Query] prefetchQuery : 데이터 선제적 로딩

 

이전 토이 프로젝트에서는 react-router 와 함께 사용하여

loader 를 이용하여 페이지가 열리기 전, 사전에 데이터를 가져오는 방법을 사용했었지만

순수하게 TanStack Query 를 사용하여 사전에 데이터를 가져오는 방법을 찾아보았습니다.

 

 

prefetchQuery & prefetchInfiniteQuery

 

https://tanstack.com/query/latest/docs/framework/react/guides/prefetching#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 (

  );
}

 

  1. useQueryClient 임포트
  2. const queryClient = useQueryClient(); 로 변수할당
  3. useEffect 사용
  4.   queryClient.prefetchQuery 를 사용하여 queryKey, queryFn 적용
          queryKey 에는 nextPage 도 함께 넣어주고
          queryFn에는  () => fetchPosts(nextPage) 로 다음 페이지 번호도 파라미터로 함께 넘겨줌
  5. 종속성 배열에는 currentPage, queryClient 추가
  6. 현재 페이지가 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 처리가 된 후, 데이터를

새로 불러오므로 의미가 없는 코드가 됩니다.