ERP-node/docs/ycshin-node/PGN[맥락]-페이징-직접입력.md

5.5 KiB

[맥락노트] 페이징 - 페이지 번호 직접 입력 네비게이션

관련 문서: 계획서 | 체크리스트


왜 이 작업을 하는가

  • 현재 페이지네이션은 1 / 38 읽기 전용 텍스트만 표시
  • 수십 페이지가 있을 때 원하는 페이지로 빠르게 이동할 수 없음 (> 연타 필요)
  • 페이지 번호를 직접 입력하여 즉시 이동할 수 있어야 UX가 개선됨

핵심 결정 사항과 근거

1. 10개 번호 버튼 그룹 → 입력 필드로 설계 변경

  • 결정: 이전 설계(10개 페이지 번호 버튼 나열)를 폐기하고, 기존 현재/총 텍스트에서 현재 부분을 입력 필드로 교체
  • 근거: 10개 버튼은 공간을 많이 차지하고 고정 슬롯/고정 너비 등 복잡한 레이아웃 제약이 발생. 입력 필드 방식이 더 직관적이고 공간 효율적
  • 이전 산출물: PageGroupNav.tsx → 삭제 완료

2. << < > >> 버튼 동작 유지

  • 결정: 4개 화살표 버튼의 동작은 기존과 완전히 동일하게 유지
  • 근거: 입력 필드가 "원하는 페이지로 점프" 역할을 하므로, 버튼은 기존의 순차 이동(+1/-1, 첫/끝) 그대로 유지하는 것이 자연스러움

3. 입력 중에는 페이지 이동 안 함

  • 결정: onChange는 입력 필드 표시만 변경. Enter 또는 blur로 실제 페이지 이동
  • 근거: 28을 입력하려면 2를 먼저 치는데, 2에서 바로 이동하면 안 됨

4. 포커스 시 전체 선택 (select all)

  • 결정: 입력 필드 클릭 시 기존 숫자를 전체 선택
  • 근거: 사용자가 "15페이지로 가고 싶다" → 클릭 → 바로 15 타이핑. 기존 값을 지우는 추가 동작 불필요

5. 유효 범위 자동 보정

  • 결정: 1 미만 → 1, totalPages 초과 → totalPages, 빈 값/비숫자 → 현재 페이지 유지
  • 근거: 에러 메시지보다 자동 보정이 UX에 유리
  • 대안 검토: 입력 자체를 숫자만 허용 → 기각 (백스페이스로 비울 때 불편)

6. inputMode="numeric" 사용

  • 결정: type="text" + inputMode="numeric"
  • 근거: type="number"는 브라우저별 스피너 UI가 추가되고, 빈 값 처리가 어려움. inputMode="numeric"은 모바일에서 숫자 키보드를 띄우면서 text 입력의 유연성 유지

7. 신규 컴포넌트 분리 안 함

  • 결정: v2-table-list의 paginationJSX 내부에 인라인으로 구현
  • 근거: 변경이 <span><input> + 핸들러 약 30줄 수준으로 매우 작음

8. currentPage를 fetch의 단일 소스로 사용

  • 결정: fetchTableDataInternal에서 tableConfig.pagination?.currentPage || currentPage 대신 currentPage만 사용
  • 근거: handlePageSizeChange에서 setCurrentPage(1) + onConfigChange(...) 호출 시, onConfigChange를 통한 부모의 tableConfig 갱신은 다음 렌더 사이클에서 전파됨. fetch가 실행되는 시점에 tableConfig.pagination?.currentPage가 아직 이전 값(예: 4)이고 truthy이므로 로컬 currentPage(1) 대신 4를 사용하게 되는 문제 발생. 로컬 currentPagesetCurrentPage로 즉시 갱신되므로 이 문제가 없음
  • 발견 과정: 페이지 크기를 20→40으로 변경하면 1페이지로 설정되지만 리스트가 빈 상태로 표시되는 버그로 발견

9. handlePageSizeChange에서 onConfigChange 호출 필수

  • 결정: 페이지 크기 변경 시 onConfigChange{ pageSize, currentPage: 1 }을 부모에게 전달
  • 근거: 기존 코드는 setLocalPageSize + setCurrentPage(1)만 호출하고 onConfigChange를 호출하지 않았음. 이로 인해 부모 컴포넌트의 tableConfig.pagination이 갱신되지 않아 후속 동작에서 stale 값 참조 가능
  • 발견 과정: 위 8번과 같은 맥락에서 발견

관련 파일 위치

구분 파일 경로 설명
수정 frontend/lib/registry/components/v2-table-list/TableListComponent.tsx paginationJSX 중앙 입력 필드 + fetch 소스 수정
삭제 frontend/components/common/PageGroupNav.tsx 이전 설계 산출물 (삭제 완료)

기술 참고

로컬 입력 상태와 실제 페이지 상태 분리

pageInputValue (string) — 입력 필드에 표시되는 값 (사용자가 타이핑 중일 수 있음)
currentPage (number) — 실제 현재 페이지 (API 호출의 단일 소스)

동기화:
- currentPage 변경 시 → useEffect → setPageInputValue(String(currentPage))
- Enter/blur 시 → commitPageInput → parseInt + clamp → handlePageChange(보정된 값)

handlePageChange 호출 흐름

입력 필드 Enter/blur
  → commitPageInput()
    → parseInt + clamp(1, totalPages)
    → handlePageChange(clampedPage)
      → setCurrentPage(clampedPage) + onConfigChange
        → useEffect 트리거 → fetchTableDataDebounced
          → fetchTableDataInternal(page = currentPage)
            → 백엔드 API 호출

handlePageSizeChange 호출 흐름

좌측 페이지크기 입력 onChange/onBlur
  → handlePageSizeChange(newSize)
    → setLocalPageSize(newSize)
    → setCurrentPage(1)
    → sessionStorage 저장
    → onConfigChange({ pageSize: newSize, currentPage: 1 })
      → useEffect 트리거 → fetchTableDataDebounced
        → fetchTableDataInternal(page = 1, pageSize = newSize)
          → 백엔드 API 호출