perf: add export loading state and virtual scrolling for large lists
Export modal now shows a loading indicator and doesn't freeze the UI. Large list modals use virtual scrolling for smooth performance.
This commit is contained in:
53
components/dashboard/VirtualList.tsx
Normal file
53
components/dashboard/VirtualList.tsx
Normal file
@@ -0,0 +1,53 @@
|
||||
'use client'
|
||||
|
||||
import { useRef } from 'react'
|
||||
import { useVirtualizer } from '@tanstack/react-virtual'
|
||||
|
||||
interface VirtualListProps<T> {
|
||||
items: T[]
|
||||
estimateSize: number
|
||||
className?: string
|
||||
renderItem: (item: T, index: number) => React.ReactNode
|
||||
}
|
||||
|
||||
export default function VirtualList<T>({ items, estimateSize, className, renderItem }: VirtualListProps<T>) {
|
||||
const parentRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
const virtualizer = useVirtualizer({
|
||||
count: items.length,
|
||||
getScrollElement: () => parentRef.current,
|
||||
estimateSize: () => estimateSize,
|
||||
overscan: 10,
|
||||
})
|
||||
|
||||
// For small lists (< 50 items), render directly without virtualization
|
||||
if (items.length < 50) {
|
||||
return (
|
||||
<div className={className}>
|
||||
{items.map((item, index) => renderItem(item, index))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div ref={parentRef} className={className} style={{ overflow: 'auto' }}>
|
||||
<div style={{ height: `${virtualizer.getTotalSize()}px`, width: '100%', position: 'relative' }}>
|
||||
{virtualizer.getVirtualItems().map((virtualRow) => (
|
||||
<div
|
||||
key={virtualRow.key}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: `${virtualRow.size}px`,
|
||||
transform: `translateY(${virtualRow.start}px)`,
|
||||
}}
|
||||
>
|
||||
{renderItem(items[virtualRow.index], virtualRow.index)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user