가상스크롤과 react-window 로 고성능 antd 테이블 만들기
최근에 리액트와 Ant Design (이하 antd)을 이용해 개발을 진행하고 있는데, 이미지 포함 1000건이 넘는 데이터를 페이지네이션 없이 한 번에 API Response로 받아 테이블로 보여줘야 하는 일이 있었다. 엄청나게 큰 데이터는 아니라 보여주는데 어려움은 없었지만 스크롤이 매끄럽지 못해 유저에게 버벅거린다는 느낌을 줄 수 있다는 생각이 들었고, 또 이미지를 한 번에 불러오다 보니 반응성이 매우 떨어지는 문제가 있었다.
그래서 혹시 antd에 이와 관련해 제공하고 있는 기능이 있는지 찾아보았는데, 다행히도 react-window에 가상 스크롤을 적용해 만들어놓은 예시가 있었다. antd table에서 제공하는 virtual list 예제를 참고해 내가 구현하려는 상황에 맞게 조금 코드를 변경해 적용하였다.
그냥 데이터를 한 번에 다 보여주면 되는 것 아닌가라고 생각할 수도 있다. 물론 그렇게 해서 보여줘도 되지만
- 만약에 데이터가 수천, 수십만 건이라면?
- 데이터에 이미지가 포함되어 있다면?
- 그 이미지를 보여주기 위해 서버에 이미지 리소스를 요청한다면?
브라우저의 성능에도 이슈가 생길 것이고 사용자는 좋지 않은 사용성을 경험하게 될 것이다.
아래 스크린샷은 컴포넌트가 마운트되었을 때 useEffect Hook에서 https://jsonplaceholder.typicode.com/photos API를 fetch 해 데이터를 가져와 테이블에 셋팅해준 화면이다. 처음 데이터를 가져오는 데 꽤나 시간이 걸리고, 모든 이미지 리소스를 요청해 셋팅하기 때문에 아이템 개수만큼 Request를 보내고 있다.
반면 react-window 라이브러리를 이용해 windowing 기법을 적용한 화면은 딱 화면에 보이는 만큼만 렌더링 되기 때문에 렌더링 하는 데 걸리는 시간을 줄일 수 있고, 사용자에게 최적화된 경험을 제공해줄 수 있다.
애플리케이션에서 긴 목록(수백 또는 수천 행)을 렌더링 하는 경우 ‘windowing’이라는 기법을 사용하는 것을 추천합니다. 이 기법은 주어진 시간에 목록의 부분 목록만 렌더링 하며 컴포넌트를 다시 렌더링 하는 데 걸리는 시간과 생성된 DOM 노드의 수를 크게 줄일 수 있습니다. (react 공식 사이트)
아래 영상을 통해 어떻게 다른지 확인해볼 수 있다.
1️⃣ 적용하지 않은 화면
2️⃣ react-window를 사용해 windowing 기법을 적용한 화면
아래 과정을 통해 위에서 본 동영상과 동일하게 구현할 수 있다.
react-window를 설치해준다. (예제에서는 1.8.7 버전을 사용함)
$npm install --save react-window
아래 예제를 참고해서 VirtualTable 컴포넌트를 생성한다.
위의 예제를 보면 antd table의 props를 그대로 받아 사용하기 때문에 import 해서 사용하는 곳에서는 편하게 사용할 수 있다.
아래는 직접 구현한 예제로 코드로 antd의 예제와 셀을 렌더링 하는 부분 (lineNumber 100~112)이 다르다. 컬럼에 render 가 있는 경우 render를, 없는 경우 셀 데이터를 텍스트로 표현해줄 수 있도록 셋팅해준다.
자세한 내용은 라인 별로 코드에 주석을 달아놓았으니 참고하면 된다.
예제에서는 Free Fake API를 사용하였다. 우연히 알게 된 API인데 이럴 때 유용하게 써먹을 수 있어서 좋은 것 같다
제공해주는 API 중에서 이미지가 있는 photo API (https://jsonplaceholder.typicode.com/photos)를 사용하였는데 이미지를 테이블에 표현해주기 위해 컬럼에 render (lineNumber: 42)를 셋팅하였다. VirtualTable에 있는 props는 antd table의 props와 동일하기 때문에 antd table API 문서를 참고해 셋팅하면 된다.