TanStack Virtualの素振り
npm install @tanstack/react-virtual@beta
- tanstack virtualは Headless UIライブラリ
- 中核にあるのが
Virtualizer
以下公式のサンプルまんま
import { useVirtualizer } from '@tanstack/react-virtual';
function App() {
// The scrollable element for your list
const parentRef = React.useRef()
// The virtualizer
const rowVirtualizer = useVirtualizer({
count: 10000,
getScrollElement: () => parentRef.current,
estimateSize: () => 35,
})
return (
<>
{/* The scrollable element for your list */}
<div
ref={parentRef}
style={{
height: `400px`,
overflow: 'auto', // Make it scroll!
}}
>
{/* The large inner element to hold all of the items */}
<div
style={{
height: `${rowVirtualizer.getTotalSize()}px`,
width: '100%',
position: 'relative',
}}
>
{/* Only the visible items in the virtualizer, manually positioned to be in view */}
{rowVirtualizer.getVirtualItems().map((virtualItem) => (
<div
key={virtualItem.key}
style={{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: `${virtualItem.size}px`,
transform: `translateY(${virtualItem.start}px)`,
}}
>
Row {virtualItem.index}
</div>
))}
</div>
</div>
</>
)
}
気になったこと
- getTotalSize()っていうAPIがあるのか
- virtualItem.sizeとかはどうやって計算しているんだ?
ReactのAPIは2つ。
function useVirtualizer<TScrollElement, TItemElement = unknown>(
options: PartialKeys<
VirtualizerOptions<TScrollElement, TItemElement>,
'observeElementRect' | 'observeElementOffset' | 'scrollToFn'
>,
): Virtualizer<TScrollElement, TItemElement>
function useWindowVirtualizer<TItemElement = unknown>(
options: PartialKeys<
VirtualizerOptions<Window, TItemElement>,
| 'getScrollElement'
| 'observeElementRect'
| 'observeElementOffset'
| 'scrollToFn'
>,
): Virtualizer<Window, TItemElement>
Virtualizer
必須なのは、要素の総数と、スクロールを行う要素と、推定サイズだけ。react-windowより少ないな。
getTotalSize
は各要素のサイズの合計を返してくれるのか。これはreact-windowより使いやすいかも。
Returns the total size in pixels for the virtualized items. This measurement will incrementally change if you choose to dynamically measure your elements as they are rendered.
VirtualItem
こっちは仮想リストの各要素。先ほどのsize
については以下のように説明がある。
The size of the item. This is usually mapped to a css property like width/height. Before an item is measured vit the VirtualItem.measureElement method, this will be the estimated size returned from your estimateSize virtualizer option. After an item is measured (if you choose to measure it at all), this value will be the number returned by your measureElement virtualizer option (which by default is configured to measure elements with getBoundingClientRect()).
最初はestimatedSizeで取得して、その後はmeasureElementオプションに則って取得する。デフォルトではgetBoundingClientRectで取得する。
公式の埋め込みのCodeSandboxがちょいちょい落ちるので、自分で作って試す。
とりあえず固定サイズのリスト(react-windowのFixedList)を作ってみたけど、こっちの方がめちゃめちゃ作りやすい。
やっぱり、sizeに関しての説明の
After an item is measured (if you choose to measure it at all), this value will be the number returned by your measureElement virtualizer option (which by default is configured to measure elements with getBoundingClientRect()).
ってのがよくわからないな。if you choose to measure it at all
っていうのが何を指しているのか。
measureオプション自体はあるけど、booleanかと思ったらただのfunctionだもんな。
要素によって高さが異なる(Dynamic)のサンプル。結構書きやすい
無限スクロールのサンプルを作っていく