문제 상황
현재 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와 성능에 직접적인 영향을 미친다는 걸 몸소 느꼈습니다.
앞으로도 단순히 “데이터를 가져오고 보여준다”라는 개념을 넘어서, *이 데이터를 사용자에게 어떻게 최적화해서 보여줄 것인가?”라는 고민을 더 깊이 해봐야겠다는 생각이 들었습니다.
'🩵 React' 카테고리의 다른 글
[React] 컴포넌트 분리 기준에 관한 고찰 (0) | 2024.11.23 |
---|---|
[React] 리액트를 사용하는 이유 (컴포넌트 분리가 왜 중요할까 ?) (0) | 2024.11.11 |
[트러블 슈팅] Geolocation API가 비정상적인 데이터를 받아올 때 (0) | 2024.08.26 |
[UI개발] Web에서 사용할 수 있는 BottomSheet를 만들어보자 ! (4) | 2024.07.22 |
[React] Geolocation API의 느린 문제 (2) - 해결방안 (3) | 2024.06.17 |