반응형
TLDR : 눈에 보이는 컴포넌트만 렌더링하자
데이터가 1억개라 생각하면, 이를 다 그리는 건 무의미하다.
사용자는 한번에 다 볼 수도 없고, 상호작용 할 수도 없다.
필요한 만큼만 그려서 최적화하자.
이것은 "virtualization" 혹은 "windowing"이라 하는 개념이며,경우에 따라 많은 데이터를 렌더링하는 컴포넌트의 성능을 개선할 수 있다.
React-virtual
https://tanstack.com/virtual/v3/docs/guide/00-introduction
1. 훅에 정보 전달하기
import { useVirtual } from "react-virtual";
const rowVirtualizer = useVirtual({
size: items.length,
parentRef: listRef,
estimateSize: React.useCallback(() => 20, []),
overscan: 10
});
.city-app ul li {
height: 20px;
}
- size : useVirtual에게 우리 리스트의 크기를 알려주고
- parentRef : 목록의 스크롤 가능한 요소에 접근할 수 있도록 하며(스크롤 가능한 요소의 높이를 이용해 몇개를 보여줄지 계산)
- estimateSize : 각 요소의 크기(px)를 알려줍니다.
- overscan : 눈에 보이는 요소 전, 후로 갖고있을 요소 갯수를 의미합니다.
2. 리스트 컴포넌트에 정보 전달하기
리스트 역할을 하는 컴포넌트에 다음과 같은 정보를 전달합니다.
- listRef : virtualizer에 전달된 리스트 컴포넌트의 레퍼런스 입니다.
- virtualRows : 렌더링할 아이템입니다.
- totalHeight : 아이템 갯수 * 픽셀 사이즈입니다.
- 우리는 100개의 아이템을 각 20px로 그릴 예정이므로 2000px이 됩니다.
<Menu
// ...
listRef={listRef}
virtualRows={rowVirtualizer.virtualItems}
totalHeight={rowVirtualizer.totalSize}
/>
3. 스타일 적용하기
여기선 약간의 조작이 필요합니다.리스트 역할을 하는 컴포넌트의 레이아웃에 position : relative를 적용합니다.
.city-app ul {
height: 300px;
width: 300px;
overflow-y: scroll;
background-color: #eee;
padding: 0;
list-style: none;
position: relative;
}
그 다음, 리스트 역할을 하는 컴포넌트의 첫번째 자식 li 컴포넌트에 아래와 같이 totalHeight를 적용해줍니다.
이는 해당 컴포넌트가 다른 li 컴포넌트들의 공간을 미리 예약해두도록 합니다.
<ul {...getMenuProps({ ref: listRef })}>
<li style={{ height: totalHeight }} /> // here~~~~~~~~~~~~~~~~~
{virtualRows.map(({ index, size, start }) => {
const item = items[index];
if (!item) return null;
return (
<ListItem
key={item.id}
getItemProps={getItemProps}
item={item}
index={index}
isSelected={selectedItem?.id === item.id}
isHighlighted={highlightedIndex === index}
style={getVirtualRowStyles({ size, start })}
>
{item.name}
</ListItem>
);
})}
</ul>
또한, 해당 라이브러리는 absolute position을 사용하여, 시작점에서 밀어주는 방식을 사용하기 때문에 아래와 같이 스타일을 적용합니다.
const getVirtualRowStyles = ({ size, start }) => ({
position: "absolute",
top: 0,
left: 0,
width: "100%",
height: size,
transform: `translateY(${start}px)`
});
클릭한 컴포넌트로 스크롤하기
// 아래 함수를 사용합니다.
rowVirtualizer.scrollToIndex(highlightedIndex)
실행해보기 :
https://react-performance.netlify.app/isolated/final/04.js
코드 보기 :
https://github.com/kentcdodds/react-performance/blob/main/src/final/04.js
아래는 downshift와 react-virtual을 같이 사용한 예제인데,
클릭 시 filter가 기능하지 않고 있음. downshift쪽 문제인것 같음.
virtualization은 정상 동작.
참고
Introducing downshift 🏎 for React ⚛️ (kentcdodds.com)
Accessibility - Learn web development | MDN (mozilla.org)
반응형
'FrontEnd' 카테고리의 다른 글
리액트 성능 최적화 : Virtual DOM (0) | 2022.06.05 |
---|---|
리액트 성능 최적화 :contextAPI (0) | 2022.06.05 |
리액트 성능 최적화 : React.memo (0) | 2022.06.05 |
리액트 성능 최적화 : React.useMemo (0) | 2022.06.04 |
리액트 디자인 패턴 : Container pattern (컨테이너 패턴) (0) | 2022.06.04 |