Skip to content

Instantly share code, notes, and snippets.

@ksk1015
Last active September 8, 2024 17:27
Show Gist options
  • Save ksk1015/19c5e182887eaa076df479efed72c1f0 to your computer and use it in GitHub Desktop.
Save ksk1015/19c5e182887eaa076df479efed72c1f0 to your computer and use it in GitHub Desktop.
ばかでか配列とかをバーチャルスクロールで表示するコンポーネント
import { useState, useDeferredValue } from 'react'
type Props<T> = {
height: number
items: T[]
maxItemCount?: number
itemHeight: number
bufferCount?: number
renderItem: (item: T, index: number) => JSX.Element
onRender?: (lastIndex: number) => void
}
export function ItemListInVirtualScroll<T>({
items,
maxItemCount = items.length,
height,
itemHeight,
bufferCount = 3,
renderItem,
onRender,
}: Props<T>) {
const [scrollY, setScrollY] = useState(0)
const startIndex = useDeferredValue(
Math.max(Math.floor(scrollY / itemHeight) - bufferCount, 0)
)
const lastIndex = Math.min(
startIndex + Math.ceil(height / itemHeight) + bufferCount * 2,
maxItemCount - 1
)
if (onRender) {
onRender(lastIndex)
}
return (
<div
style={{
height: `${height}px`,
overflowY: 'scroll',
}}
onScroll={(e) => {
setScrollY(e.currentTarget.scrollTop)
}}
>
<div style={{ height: `${itemHeight * maxItemCount - height}px` }}>
<div
style={{
translate: `0px ${startIndex * itemHeight}px`,
}}
>
{items
.slice(startIndex, lastIndex)
.map((item, index) => renderItem(item, startIndex + index))}
</div>
</div>
</div>
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment