본문 바로가기

Frontend/Tanstack Query

PrefetchQuery로 Prefetching 구현하기

Prefetching

Prefetching은 데이터가 실제로 필요하기 전에 사전에 데이터를 가져오고 캐시에 저장하는 프로세스를 말한다.
이를 통해 데이터를 미리 가져올 수 있으며, 필요할 때 데이터를 즉시 사용할 수 있다. 이는 애플리케이션의 응답성과 사용자 경험을 개선시킨다. TanStack Query에서는 prefetchQuery로 이를 구현할 수 있다.

 

prefetchQuery

prefetchQuery는 TanStack Query에서 제공하는 API 중 하나로, 사용자가 지정한 키와 옵션을 통해 데이터를 미리 가져와 캐싱한다. 이렇게 하면 해당 데이터를 사용하는 페이지나 컴포넌트가 로드될 때 즉시 데이터를 사용할 수 있어 사용자 경험이 향상된다.

 

prefetchQuery의 주요 특징

A. 데이터 미리 가져오기 : 컴포넌트가 마운트되기 전에 데이터를 로드하고 캐싱한다.
B. 사용자 경험 개선 : 초기 로딩 시간을 줄이고, 빠른 화면 전환을 제공한다.
C. 백그라운드 데이터 로딩 : 현재 화면에 표시되지 않는 데이터를 백그라운드에서 미리 가져와 준비한다.
D. 캐시 재사용 : 동일한 쿼리 키로 데이터를 요청할 경우 캐시된 데이터를 사용한다.

 

라우팅 전 데이터 미리 가져오기

// hooks/usePostDetail.js
import { useQuery } from '@tanstack/react-query';
import { fetchPostDetail } from '../api/posts';

export const usePostDetail = (postId) => {
  return useQuery({
    queryKey: ['postDetail', postId],
    queryFn: () => fetchPostDetail(postId),
  });
};

export const usePrefetchPostDetail = () => {
  const queryClient = useQueryClient();

  const prefetchPostDetail = (postId) => {
    queryClient.prefetchQuery({
      queryKey: ['postDetail', postId],
      queryFn: () => fetchPostDetail(postId),
    });
  };

  return prefetchPostDetail;
};
// components/PostsList.js
import React from 'react';
import { Link } from 'react-router-dom';
import { posts } from '../posts';
import { usePrefetchPostDetail } from '../hooks/usePrefetchPostDetail';

const PostsList = () => {
  const prefetchPostDetail = usePrefetchPostDetail();

  return (
    <ul>
      {posts.map((post) => (
        <li
          key={post.id}
          onMouseEnter={() => prefetchPostDetail(post.id)}
        >
          <Link to={`/posts/${post.id}`}>{post.title}</Link>
        </li>
      ))}
    </ul>
  );
}

export default PostsList;
// components/PostDetail.js
import { useParams } from 'react-router-dom';
import { usePostDetail } from '../hooks/usePostDetail';

const PostDetail = () => {
  const { id } = useParams();
  const { data } = usePostDetail(id);

  return (
    <div>
      <h1>{data.title}</h1>
      <p>{data.content}</p>
    </div>
  );
}

export default PostDetail;

 

페이지네이션에서 다음 페이지 미리 가져오기

// hooks/usePostList.js
import { useQuery } from '@tanstack/react-query';
import { fetchPostList } from '../api/posts';

export const usePostList = (page) => {
  return useQuery({
    queryKey: ['postList', page],
    queryFn: () => fetchPostLists(page),
  });
};

export const usePrefetchPostList = () => {
  const queryClient = useQueryClient();

  const prefetchPostList = (page) => {
    queryClient.prefetchQuery({
      queryKey: ['postList', page],
      queryFn: () => fetchPostLists(page),
    });
  };

  return prefetchPostList;
};
// components/Table.js
import React, { useEffect } from 'react';
import { usePageData } from '../hooks/usePageData';
import { usePrefetchPageData } from '../hooks/usePrefetchPageData';

const Table = () => {
  const [currentPage, setCurrentPage] = React.useState(1);
  
  const { data } = usePostList(currentPage);
  const prefetchPageData = usePrefetchPageData();

  useEffect(() => {
    prefetchPageData(currentPage + 1);
  }, [currentPage]);

  return (
    <div>
      <table>
        {... Post List}
      </table>
      <div>
        <button onClick={() => setCurrentPage((prev) => prev - 1)}>
          이전 페이지
        </button>
        <button onClick={() => setCurrentPage((prev) => prev + 1)}>
          다음 페이지
        </button>
      </div>
    </div>
  );
}

export default Table;