React.js + antd Table + react query(tanstack)으로 pagination

선다혜·2024년 1월 5일
0

pagination?

관련 링크

페이지 매김이라고도 하는 콘텐츠를 개별 페이지로 분리하는 프로세스.
페이지의 순차적 순서를 식별하기 위해 연속 번호를 추가하는 자동화된 프로세스를 의미하기도 함

나는 프로젝트에서 테이블을 조회할 때 page 단위로 조회해야 했다.

테이블은 antd 라이브러리를 사용했다. (공수 때문에 프로젝트에서 컴포넌트 상당수를 antd에서 사용)

1. 커스텀 훅 만들기

요구사항에 테이블의 행을 N개씩 볼 수 있도록 설정하는 Select 버튼이 있었다. 이걸 먼저 만들어보자.

여기서 주의해야 할 것은 Select 버튼을 눌러 viewNum을 바꾸면, 1페이지로 초기화해야 하는 것이다!

import { PaginationProps, Select } from 'antd'
import { useState } from 'react'

interface PaginationState {
  currentPage: number
  pageSize: number
}

const usePageView = () => {
  const [viewNum, setViewNum] = useState(10)

  const [pagination, setPagination] = useState<PaginationState>({
    currentPage: 1,
    pageSize: 10, // 기본 페이지 크기
  })

  const changeNum = (num: number) => {
    setViewNum(num)
    setPagination({ currentPage: 1, pageSize: num })
  }

  const onChange: PaginationProps['onChange'] = (page, pageSize) => {
    console.log(page)
    setPagination({ currentPage: page, pageSize })
  }

  const handleChange = (value: number) => {
    console.log(`selected ${value}`)
    changeNum(value)
  }

  const pageBtn = () => {
    return (
      <Select
        defaultValue={10}
        style={{ width: 'fit-content' }}
        onChange={handleChange}
        options={[
          { value: 10, label: 10 },
          { value: 20, label: 20 },
          { value: 50, label: 50 },
        ]}
      />
    )
  }

  return {
    viewNum,
    setViewNum,
    pageBtn,
    pagination: {
      current: pagination.currentPage,
      pageSize: pagination.pageSize,
      onChange,
    },
  }
}

export default usePageView

pageBtn이 Select버튼이고, 나머지는 pagination에 필요한 정보들이다.

selectBtn으로 설정한 viewNum(= pageSize)으로 pagination을 설정한다.

또한 antd은 기본적으로 pagination을 제공하는데, pageSize, total, current, onChange와 같은 속성이 필요하다.

해당 커스텀 훅이 필요한 다른 컴포넌트에서 쓰는 방법이다.

다른 페이지의 버튼을 누를 때마다 훅도 호출이 되어야 하므로 query에서도 설정해준다.

// 그 외 import 생략
import usePageView from '../../../hooks/common/usePageView'

function ProgramList() {
 
  const { viewNum, pageBtn, pagination } = usePageView()
	const { programListData } = useProgramList(viewNum, pagination.current)
  return (
        <div style={{ marginTop: '20px' }}>
          <Table
            columns={columns}
            dataSource={data}
            pagination={{
              pageSize: viewNum,
              total: totalCount, //데이터의 총 개수
              current: pagination.current,
              onChange: pagination.onChange,
            }}
          />
        </div>
  )
}

export default ProgramList

React query key를 이용하여 key가 달라질 때마다(페이지가 달라질 때마다) 쿼리를 리페칭한다.

import { useEffect } from 'react'
import { useQuery } from 'react-query'
import { useRecoilValue } from 'recoil'
import api from '../../../hooks/common/api'
import {
  diseaseSearchState,
  keywordSearchState,
  useYnsearchState,
} from '../../../store/atoms'
import { ProgramListDataType } from './list.type'

let programListData: ProgramListDataType

const useProgramList = (pageSize: number, page: number) => {
  const fetchData = async () => {
    const params = {
      page,
      pageSize,
    }

    const response = await api.get('/coaching/programs', {
      params,
    })

    return response.data
  }

  const { isLoading, error, data } = useQuery(
    ['ProgramListData', pageSize, currentPage],
    fetchData,
    {
      refetchOnWindowFocus: false, // 화면에 포커싱될떄 데이터 갱신 여부
      retry: 1, // 데이터가 안들어 왔을시에 다시 요청을 하는 횟수
      cacheTime: 1000 * 300, // 기존에 리액트쿼리가 내부적으로 가지고있는 캐시값을 몇초동안 가지고 있을지 시간 설정
      staleTime: 1000 * 20, // 데이터가 들어오고 나서 자동으로 리액트쿼리 주관하에 갱신시킬 시간.
    },
  )

  // 가공 시그니처
  if (data) programListData = data
  return { isLoading, error, programListData }
}

export default useProgramList

0개의 댓글