Tanstack Virtualとは?
Tanstack Virtualは、大きなスクロール要素を効率的にレンダリングするための仮想化ライブラリです。
どんなに多くの要素があっても、実際のDOMでは一定の数だけレンダリングする技術です。DOMにレンダリングされる要素が増えれば増えるほど、ある瞬間から性能が急激に低下するので、見せなければならない要素が多い場合、このような仮想化技法を適用することができます。
VirtualizeライブラリはTanstack以外にもreact-virtualized、react-windowなどがあります。
問題点
従来は上のようにgridで構成されていて、viewportによって表示されるカード数が変わるようにしました。
Tanstack Virtualの例を見ると分かるように、Tanstack Virtualを使うとスクロールdivの中にアイテムをabsoluteで適用して、transformを使って位置を調整するようになっています。
つまり、従来の方法では親にVirtualizerを
かぶせるだけでいいという問題ではありませんでした。Tanstack Virtualを使うと一つのrowやcolumnに一つの要素だけ入るようにする必要があります。
解決方法
既存のリストアイテムは1次元配列になっていて、これをmapを回してレンダリングしています。
const itemList = [item1, item2, item3, item4, item5, item6, item7];
return <div className='grid grid-cols-1 tablet:grid-cols-3 desktop: grid-cols-5'> >.
itemList.map(item => <card item={item} />)
</div> </div
上で説明したように一つのrowに一つの要素だけ入れる必要があるので、下記のようにコードを変更しました。
let columnSize = 3; // 1, 3, 5
const chunkedItemList = chunkArray(itemList, columnSize);
// [[item1, item2, item3], [item4, item5, item6, item7]], [item7]]].
return <div> を返します。
chunkedItemList.map(list => <div className='grid grid-cols-1 tablet:grid-cols-3 desktop: grid-cols-5'> > chunkedItemList.map(list => <div className='grid grid-cols-1 tablet:grid-cols-3 desktop: grid-cols-5'>)
{list.map(item => <card item={item} />)} }
</div>)
</div> </div> </div
既存のアイテムリストを1次元配列からcolumnSizeだけ小さい2次元配列にしました。
図で見てみるとこんな感じです。
注意しなければならないのは一行に一つの要素だけ入れること、そしてその一つの要素の中に何個のアイテムを入れるかです!
実際のコードは下記のようになります。
const [columnSize, setColumnSize] = useState(COLUMN_SIZE.desktop);
const list = chunkArray(
flatPages(data) ?? []、
columnSize
)です;
const rowVirtualizer = useVirtualizer({ {
count: list?.length、
getScrollElement: () => document.getElementById("main-section")、
estimateSize: () => 390、
overscan: 1、
}) を使用しています;
useEffect(() => { {
if (isLabtop) setColumnSize(COLUMN_SIZE.labtop);
else if (isMobile) setColumnSize(COLUMN_SIZE.mobile);
else setColumnSize(COLUMN_SIZE.desktop);
}, [isLabtop, isMobile]);
(isLabtop、isMobile); }
rowVirtualizer.getVirtualItems()?.map((virtualRow) => { {
const row = list[virtualRow.index];
if (!row) return null;
return (
<div
key={virtualRow.key}。
className={`absolute top-0 left-0 w-full`}
style={{
変換します:`translateY(${virtualRow.start}px)`、
}}
<div className="grid grid
<div className="grid grid-cols-1 laptop:grid-cols-3 desktop:grid-cols-5 w-full gap-6 place-items-center items-stretch"> </div
{row.map((item) => (
<カード
key={item.designId}
item={item}
isVault={isVault}
</i> </i><i>。
))}
</div> </div> </div
</div> </div> </div
)); </div> </div> </div> </div> </div> </div> </div
});
}
結果、下記のように特定の数だけ実際のDOMに描画されるように仮想化することができました!