🩵 React

[React] React-Window를 활용해 DOM 성능 최적화 | DOM에 요소 800개가 추가된다고 ..?

이효린 2025. 3. 12. 18:09

문제 상황

현재 BottomSheet를 활용하여 장소 정보를 표시하는 기능이 있습니다.

그러나, 장소 리스트를 제공하는 API가 페이지네이션을 지원하지 않고, 한 번에 모든 데이터를 응답하는 구조입니.

 

이로 인해 DOM을 확인해보면 모든 장소 리스트가 한 번에 렌더링되는 문제가 발생합니다.

현재 데이터베이스에는 약 800개의 장소 정보가 저장되어 있으며, 최악의 경우 800개의 장소 컴포넌트가 모두 DOM에 추가될 수 있습니다.

 

임시 데이터를 넣어둔 것이기 때문에 중복이 있습니다 !

 

이러한 문제는 다음과 같은 성능 저하를 초래할 수 있습니다.

 

1. 렌더링 성능 문제: DOM 노드가 과도하게 많아져 브라우저의 렌더링 성능이 저하됨.

2. 메모리 사용 증가: 불필요한 컴포넌트가 많아지면서 메모리 사용량이 급격히 증가함.

3. UX 저하: 스크롤이 버벅거리거나, BottomSheet가 열릴 때 지연 시간이 발생할 수 있음.

 

해결 방법

1. API 개선 요청

가장 근본적인 방법입니다. 백엔드 팀과 협의하여 페이지네이션을 지원하는 API로 개선을 요청하면 됩니다. 하지만 현재 API를 바꿀 수 있는 상황이 아닌지라.. 프론트에서 알아서 처리해야 할 것 같습니다.

 

2. 클라이언트에서 데이터 청크 처리

API를 변경할 수 없는 상황이기에, 프론트엔드에서 데이터를 일정한 크기로 나누어 (청크 단위) 점진적으로 추가하는 방식 적용할 수 있습니다.

 

⚙️ 작동 방식

  • API나 기존 데이터 배열에서 일부만 가져와 조금씩 추가적으로 렌더링
  • 사용자가 스크롤하거나 특정 이벤트 발생 시 추가 데이터를 불러옴
  • 보통 Intersection Observer 또는 스크롤 이벤트를 활용해 새로운 데이터를 추가

 

👍 장점

  • 데이터를 점진적으로 추가하여 성능 최적화 가능
  • API에서 페이지네이션을 지원하지 않더라도 클라이언트에서 제어 가능
  • 특정 시점에서 데이터가 추가되므로 UX가 자연스러움

 

 단점 

  • 추가된 데이터는 계속 DOM에 남아있어 스크롤이 길어지면 성능 저하 가능
  • 처음 데이터를 추가한 후에는 메모리 사용량이 계속 증가 → (예: 800개 데이터를 청크로 추가해도, 결국 800개가 모두 DOM에 남게 됨)
페이지네이션을 클라이언트 측에서 제어 가능하다는 장점이 있지만, 결론적으로는 800개가 모두 DOM에 남는 방식

 

3. 가상화 (Virtualization) 적용 ✅

react-window 또는 react-virtualized 같은 가상화 라이브러리를 활용해 실제 보이는 리스트만 렌더링하도록 개선할 수 있습니다.

 

⚙️ 작동 방식

  • 실제 DOM에는 화면에 보이는 요소만 추가하고, 보이지 않는 요소는 제거
  • 스크롤을 내릴 때 보이지 않는 요소를 삭제하고, 새로운 요소를 추가
  • react-window, react-virtualized 같은 라이브러리를 활용함

👍 장점

  • DOM에 유지되는 요소 개수를 최소화하여 렌더링 성능 최적화
  • 데이터 개수와 무관하게 메모리 사용량이 일정
  • 렌더링 속도가 일정하여 스크롤이 부드러움

❌ 단점

  • 가상화 처리로 인해 스크롤 위치를 유지하는 등의 UX 조정이 필요
  • 동적인 높이를 가진 리스트에서는 다루기 까다로울 수 있음
보이지 않는 요소들은 DOM에서 제거해주는 해결방안이기 때문에 가상화 방식을 채용했습니다 !
  <List 
  	height={800}
	itemCount={placeMap.length}
	itemSize={152}
	width={'100%'} >
      {({ index, style }) => (
        <div style={style}>
          <Content place={placeMap[index]} isCard={false} />
        </div>
      )}
</List>

 

 

최적화 결과

기존 모든 장소 데이터가 DOM에 추가되던 것과 대조적으로 화면에 보여지는 요소는 DOM에 추가되고 보여지지 않는 요소들은 DOM에서 제거되는 모습을 볼 수 있습니다 !

 

그리고 실제 메모리 사용률을 측정해 보았을 때 최적화 이전엔 252 MB를 사용했지만, 최적화 이후 96MB를 사용하는 것을 확인할 수 있었습니다. 

느낀점

이 문제를 해결하면서 많은 데이터를 다룰 때 단순히 데이터를 가져오는 것뿐만 아니라, DOM에 추가되는 요소의 개수까지 고려해야 한다는 점을 실감했습니다.

 

기존에는 브라우저 성능 최적화를 진행할 때는 Lazy Loading, Prefetching 과 같은 정형화된 방법만을 주로 활용했습니다. 하지만 이번 경험을 통해, DOM에 요소가 과도하게 추가될 경우 렌더링 성능이 저하될 수 있다는 문제까지 고려해야 한다는 점을 깨달았습니다.

 

프론트엔드 개발에서 데이터를 다루는 방식이 UX와 성능에 직접적인 영향을 미친다는 걸 몸소 느꼈습니다.

앞으로도 단순히 “데이터를 가져오고 보여준다”라는 개념을 넘어서, *이 데이터를 사용자에게 어떻게 최적화해서 보여줄 것인가?”라는 고민을 더 깊이 해봐야겠다는 생각이 들었습니다.