인턴

검색 페이지에서 무한 스크롤 상품 리스트 API 중복 호출 수정

jjangsh 2025. 6. 2. 15:35

개요

  • [모바일 환경] 검색 페이지에서 상품 개수가 적은 경우, 스크롤을 아래로 당길 때마다 화면이 위아래로 흔들리고, 동시에 API 요청이 무한 반복되는 현상이 발생
    • 스크롤 이벤트가 반복적으로 발생
      • 상품이 적어 페이지의 높이가 짧을 때, 스크롤 바닥 도달 조건이 계속 충족되며 getProducts 함수가 반복 호출됨
    • 데이터가 더 이상 없는데도 API 요청 지속
      • getProducts 호출 시, 더 이상 가져올 데이터가 없음을 확인하지 않아, 불필요한 API 요청이 계속 발생
    • 스켈레톤 UI 렌더링 조건 부정확
      • isFetching(상태)만으로 스켈레톤 UI 렌더링 조건을 설정해, 데이터가 없는데도 스켈레톤이 표시되고, 높이가 변경되며 스크롤 이벤트가 반복 발생

 

요구사항

  • 모바일 환경 검색 페이지에서 화면 스크롤이 지속적으로 상하 이동하며 상품 리스트 API를 호출하는 문제 개선 필요

 

작업내용

  • 더 이상 가져올 데이터가 없을 때 getProducts 실행 중단 시키기 위한 isMaxPage 상태 생성
  • getProducts 내 pageCount 비교로 isMaxPage 상태 관리
if (pageState <= res.data.pageCount) {
          dispatch(
            setProducts([...(products || []), ...(res.data?.items || [])])
          );
          dispatch(setPageState(pageState + 1));
          onChangeData("prevSearch", searchValue ? searchValue : search);
          setIsMaxPage(false);
        } else {
          setIsMaxPage(true);
        }
  • 새 검색어 입력, 검색 버튼 클릭, 필터 변경 시 isMaxPage를 false로 초기화
  • 스크롤 이벤트에서 isMaxPage 체크 추가 ( 불필요 호출 방지 )
  • isFetching && !isMaxPage일 때만 렌더링 되도록 스켈레톤 렌더링 조건 수정
{isFetching &&
        !isMaxPage &&
        [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]?.map((n) => (
          <ProductSkeletonSplit
            style={{ padding: "0px 14px 16px", gap: "10px" }}
            width={140}
            height={140}
            key={n}
            split
          />
        ))}

 

결과

 

개선 전

 

개선 후

 

회고

이번 검색 페이지 무한 스크롤 개선 작업을 진행하며, 웹과 모바일의 사용자 경험 차이가 무한 스크롤 동작에 미치는 영향을 확인했다.

 

웹은 마우스 휠로 스크롤을 내리는 방식으로 동작 범위가 상대적으로 제한되지만, 모바일은 손가락 터치로 화면을 더 크게 당길 수 있어 스크롤 이벤트가 더 자주, 더 깊게 발생하며, 이에 따라 스켈레톤 UI가 예상치 못한 시점에 렌더링되고 화면이 위아래로 흔들리는 이슈가 발생함을 확인했다.

 

같은 코드라도 사용자 환경에 따라 서로 다른 동작을 유발할 수 있다는 점을 인식했으며, 무한 스크롤 구현 시 단순히 API 호출과 로직 처리에만 집중할 것이 아니라, 모바일/웹의 동작 방식과 사용자 스크롤 패턴까지 함께 고려해야 한다는 필요성을 확인했다.

 

이번 경험을 통해 단순 기능 구현을 넘어서, 사용자 경험(UX)을 고려한 개발의 필요성을 다시 한번 인식했다.

 

향후에는 코드 작성뿐만 아니라 사용자의 실제 행동과 환경까지 함께 분석하고, 이를 바탕으로 개발해야 함을 다시 확인하는 계기가 되었다.

 

개선점으로는, 현재 무한 스크롤 로직은 window의 scroll 이벤트를 직접 핸들링하는 방식으로 구현되어 있으며, 이 방식은 스크롤 이벤트 중첩, 뷰포트 거리 계산 관리, 불필요한 렌더링 문제 등의 한계가 있었다.

 

향후에는 react-intersection-observer 라이브러리 도입 또는 IntersectionObserver API를 활용한 커스텀 훅 제작을 통해 스크롤 이벤트 의존도를 최소화하고, Tanstack Query의 useInfiniteQuery와 결합하여 보다 간결하고 안정적인 무한 스크롤 구조로 개선할 필요가 있음을 느꼈다.

 

참고

https://skynight1996.medium.com/infinite-scroll-with-react-query-and-intersection-observer-b9871eaf7248

 

Infinite Scroll with React-Query and Intersection Observer

Introduction

skynight1996.medium.com

https://tech.kakaoenterprise.com/149

 

실전 Infinite Scroll with React

시작하며 안녕하세요. 카카오엔터프라이즈 워크코어개발셀에서 프론트엔드 개발을 담당하고 있는 Denis(배형진) 입니다. 약 1년 전, 저는 프레임워크의 선택, React vs Angular 이라는 포스팅을 통해

tech.kakaoenterprise.com