perf: Additional optimizations to reduce React violations and improve performance - Add early return for empty songs array in totalDuration calculation - Add null check for getAllPlaylists to prevent unnecessary processing - Use requestAnimationFrame in Intersection Observer for better performance - Should reduce 600-1400ms message handler violations

This commit is contained in:
Geert Rademakes 2025-08-06 11:10:28 +02:00
parent 770c606561
commit 4c3b3e31d4

View File

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