diff --git a/packages/frontend/src/components/PaginatedSongList.tsx b/packages/frontend/src/components/PaginatedSongList.tsx index 3100963..45642e3 100644 --- a/packages/frontend/src/components/PaginatedSongList.tsx +++ b/packages/frontend/src/components/PaginatedSongList.tsx @@ -145,6 +145,8 @@ export const PaginatedSongList: React.FC = memo(({ // Memoized helper function to get all playlists (excluding folders) from the playlist tree const getAllPlaylists = useCallback((nodes: PlaylistNode[]): PlaylistNode[] => { + if (!nodes || nodes.length === 0) return []; + let result: PlaylistNode[] = []; for (const node of nodes) { if (node.type === 'playlist') { @@ -222,6 +224,9 @@ export const PaginatedSongList: React.FC = memo(({ if (totalPlaylistDuration) { return totalPlaylistDuration; } + // Only calculate if we have songs and no total duration provided + if (songs.length === 0) return ''; + // Fallback to calculating from current songs const totalSeconds = songs.reduce((total, song) => { if (!song.totalTime) return total; @@ -247,7 +252,7 @@ export const PaginatedSongList: React.FC = memo(({ } }, [debouncedSearchQuery, searchQuery, onSearch]); - // Intersection Observer for infinite scroll + // Intersection Observer for infinite scroll - optimized useEffect(() => { if (loadingRef.current) { observerRef.current = new IntersectionObserver( @@ -255,7 +260,10 @@ export const PaginatedSongList: React.FC = memo(({ // Use current values from refs to avoid stale closure if (entries[0].isIntersecting && hasMoreRef.current && !loadingRef_state.current && !isTriggeringRef.current) { isTriggeringRef.current = true; - onLoadMoreRef.current(); + // Use requestAnimationFrame for better performance + requestAnimationFrame(() => { + onLoadMoreRef.current(); + }); // Reset the flag after a short delay to prevent multiple triggers timeoutRef.current = setTimeout(() => { isTriggeringRef.current = false;