import { memo, type ReactNode } from 'react' import { Film } from 'lucide-react' import { MediaCard } from '../components/MediaCard' import { MEDIA_GRID_CLASS, VirtualMediaGrid } from '../components/VirtualMediaGrid' import type { Media } from '../types' import type { SeriesCard } from '../utils/groupSeries' // 超过该数量后切换为虚拟滚动:DOM 只挂载视口内的卡片,大库不再线性劣化。 const VIRTUALIZE_THRESHOLD = 200 type LibraryMediaSectionsProps = { isSeries: boolean items: Media[] seriesCards: SeriesCard[] selectedSeries: SeriesCard | null loading: boolean cardActions: (media: Media) => ReactNode onSeriesClick: (series: SeriesCard) => void } export function LibraryMediaSections({ isSeries, items, seriesCards, selectedSeries, loading, cardActions, onSeriesClick, }: LibraryMediaSectionsProps) { return ( <> {!isSeries && items.length > 0 && ( { const media = items[index] // renderActions 传函数引用:MediaCard 重渲染时才构建操作按钮, // 配合 memo,父级无关状态变化不再级联重渲染全部卡片。 return }} /> )} {!isSeries && items.length === 0 && ( )} {isSeries && seriesCards.length > 0 && !selectedSeries && ( { const series = seriesCards[index] return ( ) }} /> )} {isSeries && seriesCards.length === 0 && !loading && ( )} ) } // 独立 memo 组件:onClick 闭包在其内部创建,props 均为稳定引用, // 父级重渲染不会穿透到每张剧集卡片。 const SeriesCardItem = memo(function SeriesCardItem({ series, cardActions, onSeriesClick, }: { series: SeriesCard cardActions: (media: Media) => ReactNode onSeriesClick: (series: SeriesCard) => void }) { return ( onSeriesClick(series)} /> ) }) function MediaGrid({ count, renderItem }: { count: number; renderItem: (index: number) => ReactNode }) { if (count <= VIRTUALIZE_THRESHOLD) { return
{Array.from({ length: count }, (_, index) => renderItem(index))}
} return } function LibraryEmptyState({ message }: { message: string }) { return (

{message}

) }