우측은 피그마 디자인인데, 페이지네이션이 있다는 걸 확인했다. 

 

앞서 무한스크롤을 구현할때, useInfiniteQuery를 썼었다.

 

https://evan6-6.tistory.com/79

 

무한 스크롤 feat. useInfiniteQuery, Observer

일단 퍼블 단계에서는 Axios로 첫번째 페이지만 가져와서 뿌려준 상태였다. 또한 Query에서 상태관리도 안되구... 근데 알아보니까 React Query에 페이징에 특화된 훅이 있었다. useInfiniteQuery... https://ta

evan6-6.tistory.com

 

이 Hook은 API 요청 반환값에서 Page와 PageParams를 캐시에 저장합니다.

그리고 다음,이전페이지 같은것을 감지 해서 알아서 boolean으로 뱉어주고 약간 

무한스크롤과 페이지네이션에 최적화 되어있다고 생각한다.

 

그래서 처음에 useInfiniteQuery를 활용해서 페이지네이션을 구현하려고 했는데,

문제가 생겼었다. 

이런식으로 이전, 다음페이지로 가는 버튼만 존재한다면 이 훅이 최고라고 생각한다. 

하지만 디자인 시스템에서 요구한 페이지네이션은 숫자가 있다.

 

이러면 살짝 문제가 생긴다. 

 

order/status/?page=${pageParam}&page_size=4

 

1. 반환값 

일단 첫번째로 다음페이지에 대한 반환값이 통 url로 넘어온다. 그래서 첫 pageParam을 URL을 줘버리면 fetchNextPage, fetchPreviousPage가 잘 되겠지만, 숫자를 클릭했을대한 처리를 어찌해야할지 잘 몰랐었다.

 

pageParam에 page라는 State로 관리하면서 바꿔주면서 페이지마다의 정보를 가져오는 것을 상상했지만,

그렇다면 애초에 왜 useInfiniteQuery가 필요한것인가 ..? 

그래서 useQuery로 바꾸기로 정했다. 

다 바꾸고 나서 알게 된거지만 react-query 공홈에서도 useQuery로 사용하더이다.. 

 

https://tanstack.com/query/v4/docs/guides/paginated-queries

 

Paginated / Lagged Queries | TanStack Query Docs

Rendering paginated data is a very common UI pattern and in React Query, it "just works" by including the page information in the query key: `tsx

tanstack.com

const [page, setPage] = useState(1);

 const { data: PageInfo, isLoading } = useQuery(
   [QUERY_KEY.MYORDERS, page],
   () => getMyOrders(page),
   { keepPreviousData: true },
 );

 

여기서 KeppPreviousData를 True로 해줬는데 의미는 이렇다.

쿼리 키가 변경되어서 새로운 데이터를 요청하는 동안에도 마지막 data값을 유지한다. 페이지네이션을 구현할 때 유용하다. 캐시되지 않은 페이지를 가져올 때 화면에서 목록이 사라지는 깜빡임 현상을 방지할 수 있다. isPreviousData 값으로 현재의 쿼리 키에 해당하는 값인지 확인할 수 있다.

그리고 페이지 바를 두 페이지에서 공통으로 사용하고 있어서 컴포넌트로 빼놨다. 

문제는 페이지가 바꿀때마다, 위치를 바꿔줘야하는데, 이는 조금 무식하지만 코드를 짜서 구현해 봤다.

  const pagenation = useCallback(
    (total) => {
      const newArr = [];
      if (page > 3 && page < total - 2) {
        for (let i = page - 2; i <= page + 2; i++) newArr.push(i);
      } else if (page <= 3) {
        for (let i = 1; i <= 5; i++) newArr.push(i);
      } else if (page >= total - 2) {
        for (let i = total - 4; i <= total; i++) newArr.push(i);
      }
      return newArr;
    },
    [page],
  );

  useEffect(() => {
    if (total > 5) setPageNum(pagenation(total));
    else setPageNum(Array.from({ length: total }, (_, i) => i + 1));
  }, [page, total]);

나같은 경우는 처음 페칭하고 나서 총 수량을 페이지당 results 갯수로 나눠서 컴포넌트에 total이라는 페이지 값을 꽂아줬다.

그걸로  Array를 만들어 Map을 돌려 버튼을 만들었는다. 그리고 page가 바뀔때마다 useEffect가 발동해서 처리해준다.

 

결과물