[React-Query 02] 리액트 쿼리로 페이지네이션 작업하기

📄 페이지네이션 작업에 리액트 쿼리가 하는 일

페이지네이션 작업에서 다음 페이지 버튼을 눌렀을 경우에 리액트는 새로운 데이터를 불러오기 위해 api를 호출합니다.

이때 사용자는 데이터를 불러오는 시간만큼 기다려야 하기 때문에 사용자 경험이 안좋아지는 결과를 초래합니다.

리액트 쿼리를 사용해 호출 가능성이 있는 데이터를 미리 불러오는 작업, 즉 프리페칭(Prefetching)을 사용해 미리 다음 페이지의 데이터를 불러온다면 사용자는 페이지에 나타날 정보를 위해 기다릴 필요성이 사라지게 됩니다.

📌 프리페칭(Prefetching)이란? 호출 가능성이 있는 데이터를 미리 불러오는 작업. 데이터를 미리 불러와 캐시에 데이터를 저장한다.

📄 리액트 쿼리로 페이지네이션 구현하기

1. 쿼리 설정하기

페이지네이션을 위해 쿼리를 설정합니다.

페이지 별 게시글을 불러오는 함수를 쿼리함수로 설정했는데 이때 쿼리키를 동일하게 한다면 모든 페이지가 같은 정보를 표시하게 됩니다.

쿼리키를 동일하게 했을 경우 어떤 트리거가 있어야만 데이터를 리페칭할 수 있는데 다음 페이지 버튼을 클릭한다고 트리거가 발생하지 않습니다.

트리거가 발생하는 기준은 다음과 같습니다.

  1. 컴포넌트 리마운트
  2. 윈도우 리포커징
  3. 리페칭함수 실행
  4. 자동 리페칭
  5. mutation 이후 쿼리 무효화

이전/다음 버튼을 클릭했을 때 트리거가 발생하도록 쿼리키를 배열로작성했습니다.

const { data, isError, error, isLoading } = useQuery(
  ["posts", currentPage], // 🎉
  () => fetchPosts(currentPage),
  {
    staleTime: 2000,
    keepPreviousData: true,
  }
);
if (isLoading) return <h3>Loading...</h3>;
if (isError)
  return (
    <>
      <h3>Oops, something went wrong</h3>
      <p>{error.toString()}</p>
    </>
  );

📌 keepPreviousData: 새 데이터가 요청되는 동안 마지막으로 성공한 fetch Data로 유지해 사용자 경험을 향상시킬 수 있다.

2. 프리페칭 함수 설정하기

현재 페이지가 변경될 때마다 프리페칭 함수를 실행시키기 위해 useEffect함수를 사용합니다.

useEffect(() => {
  if (currentPage < maxPostPage) {
    const nextPage = currentPage + 1;
    queryClient.prefetchQuery(["posts", nextPage], () => fetchPosts(nextPage));
  }
}, [currentPage, queryClient]);

최대 페이지 (maxPostPage)에서는 실행되지 않도록 if 조건문을 사용했습니다.

쿼리를 설정했을 때와 마찬가지로 쿼리키를 배열로 설정합니다.

3. return 함수 작성하기

각 버튼의 disabled 속성을 이용해 페이지가 1일 경우, 최대 페이지일 경우에 버튼이 비활성화 되도록 설정합니다.

<div className="pages">
  <button
    disabled={currentPage <= 1}
    onClick={() => {
      setCurrentPage((previosValue) => previosValue - 1);
    }}
  >
    Previous page
  </button>
  <span>Page {currentPage}</span>
  <button
    disabled={currentPage >= maxPostPage}
    // onClick함수에 프리페칭 작업을 하지 않는 이유: setState함수는 비동기로 실행되기 때문에 현재 페이지가 무엇인지 정확히 알 방법이 없다.
    onClick={() => {
      setCurrentPage((previousValue) => previousValue + 1);
    }}
  >
    Next page
  </button>
</div>

프리페칭 함수를 onClick함수에 바로 작성하지 않은 이유가 있습니다.

setState함수는 비동기로 실행되기 때문에 프리페칭이 진행될 시점에는 현재 페이지가 무엇인지 정확히 알 방법이 없기 때문입니다.

따라서 useEffect의 의존성 배열에 조건을 걸어 프리페칭이 실행되도록 하는 것이 적합합니다.

참고

Leave a comment