usePagination: 3줄 코드, 무한한 가능성

발행: (2026년 6월 5일 PM 08:05 GMT+9)
8 분 소요
원문: Dev.to

출처: Dev.to

페이지네이션이 적용된 리스트는 프론트엔드 개발에서 가장 흔한 패턴 중 하나입니다. 페이지, 페이지당 아이템 수, 전체 개수, 로딩, 에러 상태 관리와 페이지네이션, 검색 디바운스, 아이템 변형을 위한 핸들러까지 손수 구현하면 50줄이 넘는 코드가 쉽게 만들어집니다. alova의 usePagination 훅은 이를 대략 3줄의 설정으로 압축합니다. 이 글에서는 추상화가 어떻게 동작하는지, 그리고 어디에 적합한지 살펴봅니다.

아래는 Vue 3와 Axios를 사용해 작성한 일반적인 페이지네이션 리스트 예시입니다.

const list = ref([]);
const loading = ref(false);
const error = ref(null);
const page = ref(1);
const pageSize = ref(10);
const total = ref(0);
const searchKeyword = ref('');

const fetchList = async () => {
  loading.value = true;
  error.value = null;
  try {
    const res = await axios.get('/api/users', {
      params: {
        page: page.value,
        pageSize: pageSize.value,
        keyword: searchKeyword.value,
      },
    });
    list.value = res.data.data;
    total.value = res.data.total;
  } catch (e) {
    error.value = e.message;
  } finally {
    loading.value = false;
  }
};

const changePage = (p) => { page.value = p; fetchList(); };
const changePageSize = (ps) => { pageSize.value = ps; page.value = 1; fetchList(); };
const onSearch = (keyword) => { searchKeyword.value = keyword; page.value = 1; fetchList(); };
const deleteItem = async (id) => { await axios.delete(`/api/users/${id}`); fetchList(); };

onMounted(() => fetchList());

실제 비즈니스 로직—GET /api/users—은 한 줄에 불과합니다. 나머지 50줄 이상은 인프라스트럭처(상태 연결, 로딩 토글, 페이지네이션 조정, 필터 초기화) 역할을 합니다. 이 패턴은 프로젝트 전반의 모든 리스트 페이지에서 반복됩니다.

usePagination은 그 모든 인프라스트럭처를 내부화합니다.

import { usePagination } from 'alova/client';

const searchKeyword = ref('');

const {
  loading, data, error,
  page, pageSize, total, pageCount, isLastPage,
  fetching, removing, replacing, status,
  refresh, insert, remove, replace, reload,
  onSuccess, onError, onComplete,
} = usePagination(
  (page, pageSize) => alovaInstance.Get('/api/users', {
    params: { page, pageSize, keyword: searchKeyword.value },
  }),
  {
    initialPage: 1,
    initialPageSize: 10,
    watchingStates: [searchKeyword],
    debounce: 300,
  }
);

3줄의 설정이 50줄 이상의 명령형 코드를 대체합니다. 얻을 수 있는 장점은 다음과 같습니다.

  • page.value 혹은 pageSize.value를 수정하면 자동으로 요청이 발생합니다. pageSize를 바꾸면 페이지가 1로 초기화되고, 별도의 연결 코드가 필요 없습니다.

    page.value = 3;       // 페이지 3을 자동으로 가져옴
    pageSize.value = 20; // 페이지 1로 초기화하고 자동으로 가져옴
  • watchingStates에 반응형 상태를 추가하고(옵션 디바운스 포함) 하면, 필터가 바뀔 때마다 리스트가 다시 조회됩니다.

    searchKeyword.value = 'John';  // 300ms 디바운스 후 페이지 1부터 자동 조회
  • insert, remove, replace 로컬 리스트를 업데이트하면서 서버와 동기화합니다—수동 재조회가 필요 없습니다.

    await insert({ id: 99, name: 'New User' }, 0);       // 앞에 삽입
    await remove(2);                                     // 3번째 아이템 삭제
    await replace({ id: 5, name: 'Updated' }, 4);        // 5번째 아이템 교체
    await refresh(page.value);                           // 현재 페이지 강제 새로고침
    await reload();                                      // 초기화 후 페이지 1부터 다시 로드
  • 기본적으로 다음·이전 페이지가 백그라운드에서 미리 로드됩니다. 사용자가 “다음 페이지”를 클릭하면 데이터가 이미 캐시돼 있어 로딩 스피너가 나타나지 않습니다.

  • 단일 로딩 플래그를 넘어, usePagination은 작업별 상태를 노출합니다.

    • loading    // 현재 페이지 로딩 중
    • fetching   // 백그라운드 프리로드 (UI 차단 안 함)
    • removing  // 현재 삭제 중인 행 인덱스 배열
    • replacing  // 교체 중인 행 인덱스
    • status   // 현재 작업: "loading" | "removing" | "inserting" | "replacing"

    이를 통해 삭제 중인 행만 로딩 표시를 하고, 나머지 리스트는 그대로 인터랙티브하게 유지할 수 있습니다.

코드 감소의 근본 원리

구분수동 구현usePagination
코드 양50~60줄~3줄 설정
페이지네이션 로직페이지와 요청을 직접 관리상태 변화에 자동 응답
검색 디바운스직접 구현watchingStates + debounce
리스트 변형각 작업 후 재조회낙관적 insert/remove/replace
프리로드직접 구현기본 제공, 자동 활성화
로딩 세분화단일 Boolean다중 레벨: loading/fetching/removing/replacing
커스터마이징 한계완전 자유훅 설계에 의해 제한
학습 곡선프레임워크 기본 지식훅 설정 및 동작 이해

언제 사용하고 언제 피해야 할까?

  • 적합한 경우

    • 표준 CRUD 관리 화면(사용자 리스트, 주문 테이블, 콘텐츠 관리 등)
    • 페이지네이션·검색·인라인 CRUD가 동시에 필요한 경우
    • 여러 필터가 페이지네이션을 리셋해야 하는 상황
    • 빈번한 아이템 변형(인라인 편집, 삭제, 삽입)으로 낙관적 업데이트가 유리한 경우
    • API 응답 형태가 { data: [], total: number }와 같이 일반적인 형태인 경우
  • 제한이 있는 경우

    • 커서 기반 페이지네이션(after/before 커서) – 페이지 번호 모델에 바로 매핑되지 않음
    • 양방향 무한 스크롤(채팅 히스토리 등) – 훅 설계 범위를 초과
    • 여러 리스트가 동시에 업데이트되어야 하는 복잡한 순서 제어가 필요한 경우
    • 여러 엔드포인트에서 데이터를 조합해야 하는 경우(데이터/전체 개수 콜백으로 매핑 불가)

usePagination이 스스로 할 수 없는 일을 할 수 있는 것은 아닙니다. 그 가치는 검증된 페이지네이션 구현을 패키징해 줌으로써, 매 리스트 페이지마다 동일한 50줄을 작성·디버깅할 필요가 없다는 데 있습니다. 표준 페이지네이션 사용 사례에서는 보일러플레이트 감소와 내장 프리로드·낙관적 업데이트가 눈에 띄는 개선을 제공합니다. 설계 범위를 벗어나는 상황에서는 직접 구현하는 것이 더 명확한 선택이 될 수 있습니다.

0 조회
Back to Blog

관련 글

더 보기 »

모바일 한여름 열풍

!Cover image for Mobile Midsommer Madnesshttps://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploa...