lifecarelog
프론트엔드

기록 수백 개에서 스크롤이 버벅일 때, 리스트 가상화 도입기

기록이 수백 개로 늘며 버벅이던 스크롤을, 안 보이는 항목은 안 그리는 리스트 가상화로 매끄럽게 만든 프론트엔드 구현기예요.

4분 읽기

기록 수백 개에서 스크롤이 버벅일 때, 리스트 가상화 도입기

기록이 몇 개일 때는 아무 문제가 없었어요. 그런데 항목이 수백 개로 늘어나니 스크롤을 내릴 때마다 화면이 한 박자씩 밀리더라고요. 혹시 이런 적 없나요?

왜 느려질까

원인은 단순했어요. 화면에는 15개 안팎만 보이는데, 브라우저는 안 보이는 나머지 수백 개까지 전부 DOM으로 그리고 있었거든요.

직접 항목 500개를 한 번에 뿌려 보니, 크롬 개발자 도구 성능 탭에서 스크롤 한 번에 프레임이 뚝뚝 끊겼어요. 화면이 부드럽게 움직이려면 60fps, 그러니까 프레임 하나를 약 16밀리초 안에 마쳐야 하는데 그걸 넘겨 버린 거예요.

전체 렌더링과 가상화 렌더링의 DOM 노드 수 차이

리스트 가상화라는 발상

가상화는 이름이 거창하지만 생각은 게을러요. "안 보이는 건 안 그린다."

스크롤 위치를 계산해서 지금 화면에 걸치는 항목만 실제로 그리고, 나머지 자리는 빈 높이로만 채워 두는 방식이에요. 항목이 500개여도 실제로 DOM에 올라가는 건 20개 안팎으로 줄어들죠.

스크롤 위치 감지보이는 범위 계산해당 항목만 렌더

리액트라면 react-window나 TanStack Virtual 같은 라이브러리가 이 계산을 대신해 줘요. 스크롤 이벤트를 직접 다 짜지 않아도 되니 편했어요. 항목 높이가 제각각이면 동적 높이 옵션을 켜면 되고요.

적용하면서 챙긴 것들

두 가지만 신경 썼어요.

하나는 overscan이에요. 화면 위아래로 여유분을 몇 개(보통 5개 정도) 미리 그려 두면, 빠르게 스크롤할 때 빈 칸이 잠깐 번쩍이는 걸 막을 수 있어요.

다른 하나는 항목 컴포넌트의 key였어요. 인덱스를 key로 쓰면 스크롤 중에 항목이 재사용되면서 엉뚱한 데이터가 잠깐 보이더라고요. 고유 id를 key로 바꾸니 깔끔해졌어요.

가상화를 적용하고 다시 스크롤을 돌려 보니, 수백 개짜리 목록도 처음 몇 개일 때처럼 매끄럽게 넘어갔어요.

마무리

플랜비(plan-b)로 동호회를 운영하다 보면 출전 기록이나 회비 내역이 계속 쌓여요. 목록이 길어질수록 이 가상화가 쓸모가 커지더라고요.

테스트해 보면 알겠지만, 항목이 수십 개 수준이라면 굳이 넣을 필요는 없어요. 화면이 실제로 버벅이기 시작할 때 꺼내 쓰는 도구로 남겨 두면 충분해요. 필요한 곳에만 두는 게 제일 게으르고 좋은 방법이에요.

#리스트 가상화#프론트엔드#스크롤 성능

라이프케어로그 서비스가 궁금하신가요?

AI 기반 건강·일정·재활 관리 앱을 직접 써보세요.

서비스 살펴보기

관련 글

댓글

아직 댓글이 없어요. 첫 댓글을 남겨주세요.