토스 앱 웹뷰에서 대량 리스트 스크롤을 TanStack Virtual로 최적화한 이야기
토스 앱 내 웹뷰로 동작하는 서비스(카모)를 개발하면서, 매장 상세 페이지에 들어갈 때마다 스크롤이 버벅이는 이슈를 만났습니다. 메뉴가 많은 매장일수록 심했습니다. 수백 개 단위의 메뉴를 가진 매장을 열면 초기 렌더에 수 초가 걸리고, 스크롤 중에는 명백한 프레임 드롭이 눈에 띄었습니다.

웹도 아니고 네이티브 앱도 아닌 "앱 안의 웹뷰" 라는 특성상, 토스 앱을 쓰는 사용자는 자연스럽게 네이티브 수준의 부드러움을 기대합니다. 여기서 "로딩이 느려요" 혹은 "스크롤이 뚝뚝 끊겨요" 가 되면 서비스 신뢰도가 한 번에 떨어집니다.
왜 대량 리스트에서 스크롤이 느려지나
문제를 뜯어보면 원인은 간단합니다. 브라우저는 DOM에 들어 있는 모든 노드를 레이아웃 계산·스타일 계산·페인트하려고 합니다. 메뉴 아이템 하나가 썸네일 이미지 + 이름 + 설명 + 가격 + 버튼으로 구성된다면, 한 아이템당 DOM 노드 수십 개가 만들어집니다. 500개 메뉴면 수만 개 노드입니다.
모바일 웹뷰 환경(특히 저사양 안드로이드)에서 이 규모의 DOM은 꽤 무겁습니다. 게다가 이미지가 각자 비동기 로드되면서 레이아웃이 계속 재계산되면 스크롤 중 jank가 발생합니다.
해결책: 뷰포트만 그리자
핵심 아이디어는 단순합니다. 화면에 보이는 영역 + 약간의 버퍼만 DOM에 유지하고, 나머지는 그리지 않는다. 가상 스크롤(virtualization)이라고 부릅니다.

이걸 직접 구현하면 꽤 복잡합니다. 뷰포트 좌표 계산, 스크롤 이벤트 throttle, 아이템 높이 측정, 동적 높이 변경 대응, scroll restoration까지. 그래서 검증된 라이브러리를 쓰는 게 맞고, React 환경에서 가장 깔끔한 선택이 TanStack Virtual입니다.
TanStack Virtual 선택 이유
카모 프로젝트에선 이미 TanStack Router와 TanStack Query를 쓰고 있었습니다. 같은 계열의 Virtual은 다음 장점이 있습니다.
- 작고 단일 책임에 충실 — "리스트 가상화"만 하고 UI를 강제하지 않습니다
- React 전용 훅 제공 —
useVirtualizer하나로 대부분 케이스 커버 - 동적 높이 지원 —
measureElement로 실제 DOM 높이를 측정 - SSR 안전 — 초기 HTML도 의미 있는 렌더링 가능
- 활발한 유지보수 + 문서 풍부
구현 — 핵심만
카모 메뉴 리스트의 가장 단순화한 형태입니다.
핵심은 세 가지입니다:
getTotalSize()로 전체 스크롤 영역 확보getVirtualItems()가 돌려주는 뷰포트 근처 아이템만 렌더measureElement로 실제 DOM 높이 측정 → 동적 이미지 로딩 대응
마주친 함정들
1. 이미지 lazy 로딩 시 높이 점프
메뉴 아이템의 썸네일이 lazy 로드되면 아이템 높이가 나중에 커집니다. 이걸 처리 안 하면 스크롤이 이상하게 튑니다. measureElement를 쓰되, 이미지 onLoad에서 rowVirtualizer.measure()를 다시 호출하도록 훅을 걸어줬습니다.
2. 카테고리 헤더 + 아이템 혼재
메뉴는 "커피 · 논커피 · 티/라떼 · 디저트" 같은 카테고리 헤더와 아이템이 섞여 있습니다. TanStack Virtual은 가변 높이를 지원하므로 같은 virtualizer 안에서 타입을 분기해서 렌더하면 됩니다.
3. Scroll Restoration
상세 페이지 들어갔다가 돌아올 때 스크롤 위치가 리셋되면 유저 경험이 깨집니다. TanStack Router의 scroll restoration과 Virtual의 scrollToIndex를 조합해서 복귀 시 이전 스크롤 위치로 jump 시켰습니다.
결과

- 초기 렌더 시간이 아이템 수와 무관하게 일정해졌습니다
- 스크롤 중 프레임 드롭 사라짐, 저사양 안드로이드 웹뷰에서도 일관된 부드러움
- 메뉴 수가 1000개를 넘어도 성능 저하 없음
언제 가상 스크롤을 도입할까

- 도입 추천: 모바일 웹/웹뷰 + 아이템이 100개 이상 + 이미지/복잡 UI 포함 리스트
- 굳이 필요 없음: 데스크톱 + 짧은 리스트(50개 미만) + 정적 콘텐츠
- 주의: SEO가 중요한 페이지면 초기 HTML에 뭐가 보여야 하는지 설계 필요
마치며
가상 스크롤은 "당연히 쓰면 되는 최적화"처럼 보이지만, 실제 도입할 땐 이미지 로딩·동적 높이·scroll restoration 같은 실전 함정이 꽤 있습니다. 특히 토스 앱 웹뷰처럼 "네이티브 앱에 얹힌 웹" 환경에서는 자잘한 UX 결함이 앱 전체 인상에 영향을 주기 때문에, 이런 최적화 하나하나가 서비스 신뢰도와 직결됩니다.
FE 엔지니어로서 라이브러리 선택, 함정 파악, 성능 체감 개선까지 한 사이클을 돈 경험이었습니다.
junsobi
2026년 4월 19일