perf: Aggressive optimization for playlist switching to make it snappy - Add React.startTransition to batch state updates in usePaginatedSongs - Optimize playlist selection handler with immediate navigation - Memoize click handlers in PlaylistItem to prevent recreation - Use replace navigation to avoid history stack delays - Should dramatically reduce 600+ms playlist switching delay
This commit is contained in:
parent
c9541cffee
commit
770c606561
@ -1,6 +1,6 @@
|
|||||||
import { Box, Button, Flex, Heading, Spinner, Text, useBreakpointValue, IconButton, Drawer, DrawerBody, DrawerHeader, DrawerOverlay, DrawerContent, useDisclosure, Modal, ModalOverlay, ModalContent, ModalHeader, ModalBody, ModalFooter, VStack } from "@chakra-ui/react";
|
import { Box, Button, Flex, Heading, Spinner, Text, useBreakpointValue, IconButton, Drawer, DrawerBody, DrawerHeader, DrawerOverlay, DrawerContent, useDisclosure, Modal, ModalOverlay, ModalContent, ModalHeader, ModalBody, ModalFooter, VStack } from "@chakra-ui/react";
|
||||||
import { ChevronLeftIcon, ChevronRightIcon, SettingsIcon } from "@chakra-ui/icons";
|
import { ChevronLeftIcon, ChevronRightIcon, SettingsIcon } from "@chakra-ui/icons";
|
||||||
import { useState, useRef, useEffect, useCallback } from "react";
|
import React, { useState, useRef, useEffect, useCallback } from "react";
|
||||||
import { useNavigate, useLocation, Routes, Route } from "react-router-dom";
|
import { useNavigate, useLocation, Routes, Route } from "react-router-dom";
|
||||||
import { PaginatedSongList } from "./components/PaginatedSongList";
|
import { PaginatedSongList } from "./components/PaginatedSongList";
|
||||||
import { PlaylistManager } from "./components/PlaylistManager";
|
import { PlaylistManager } from "./components/PlaylistManager";
|
||||||
@ -154,13 +154,15 @@ export default function RekordboxReader() {
|
|||||||
}, [currentPlaylist, playlists, navigate, xmlLoading]);
|
}, [currentPlaylist, playlists, navigate, xmlLoading]);
|
||||||
|
|
||||||
const handlePlaylistSelect = (name: string) => {
|
const handlePlaylistSelect = (name: string) => {
|
||||||
setSelectedSong(null); // Clear selected song when changing playlists
|
// Clear selected song immediately to prevent stale state
|
||||||
|
setSelectedSong(null);
|
||||||
|
|
||||||
|
// Navigate immediately without any delays
|
||||||
if (name === "All Songs") {
|
if (name === "All Songs") {
|
||||||
navigate("/");
|
navigate("/", { replace: true });
|
||||||
} else {
|
} else {
|
||||||
// Use encodeURIComponent to properly handle spaces and special characters
|
|
||||||
const encodedName = encodeURIComponent(name);
|
const encodedName = encodeURIComponent(name);
|
||||||
navigate(`/playlists/${encodedName}`);
|
navigate(`/playlists/${encodedName}`, { replace: true });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -101,6 +101,15 @@ const PlaylistItem: React.FC<PlaylistItemProps> = React.memo(({
|
|||||||
allFolders,
|
allFolders,
|
||||||
}) => {
|
}) => {
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
|
||||||
|
// Memoize click handlers to prevent recreation
|
||||||
|
const handlePlaylistClick = useCallback(() => {
|
||||||
|
onPlaylistSelect(node.name);
|
||||||
|
}, [onPlaylistSelect, node.name]);
|
||||||
|
|
||||||
|
const handleFolderToggle = useCallback(() => {
|
||||||
|
setIsOpen(prev => !prev);
|
||||||
|
}, []);
|
||||||
const indent = level * 10; // Reverted back to 10px per level
|
const indent = level * 10; // Reverted back to 10px per level
|
||||||
|
|
||||||
if (node.type === 'folder') {
|
if (node.type === 'folder') {
|
||||||
@ -110,7 +119,7 @@ const PlaylistItem: React.FC<PlaylistItemProps> = React.memo(({
|
|||||||
<Button
|
<Button
|
||||||
flex={1}
|
flex={1}
|
||||||
{...unselectedButtonStyles}
|
{...unselectedButtonStyles}
|
||||||
onClick={() => setIsOpen(!isOpen)}
|
onClick={handleFolderToggle}
|
||||||
ml={indent}
|
ml={indent}
|
||||||
pl={level > 0 ? 6 : 4} // Add extra padding for nested items
|
pl={level > 0 ? 6 : 4} // Add extra padding for nested items
|
||||||
justifyContent="flex-start"
|
justifyContent="flex-start"
|
||||||
@ -178,7 +187,7 @@ const PlaylistItem: React.FC<PlaylistItemProps> = React.memo(({
|
|||||||
<Button
|
<Button
|
||||||
flex="1 1 auto"
|
flex="1 1 auto"
|
||||||
{...(selectedItem === node.name ? selectedButtonStyles : unselectedButtonStyles)}
|
{...(selectedItem === node.name ? selectedButtonStyles : unselectedButtonStyles)}
|
||||||
onClick={() => onPlaylistSelect(node.name)}
|
onClick={handlePlaylistClick}
|
||||||
ml={indent}
|
ml={indent}
|
||||||
pl={level > 0 ? 6 : 4} // Add extra padding for nested items
|
pl={level > 0 ? 6 : 4} // Add extra padding for nested items
|
||||||
borderRightRadius={0}
|
borderRightRadius={0}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { useState, useEffect, useCallback, useRef } from 'react';
|
import React, { useState, useEffect, useCallback, useRef } from 'react';
|
||||||
import { api, type SongsResponse } from '../services/api';
|
import { api, type SongsResponse } from '../services/api';
|
||||||
import type { Song } from '../types/interfaces';
|
import type { Song } from '../types/interfaces';
|
||||||
|
|
||||||
@ -138,21 +138,24 @@ export const usePaginatedSongs = (options: UsePaginatedSongsOptions = {}) => {
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Handle playlist changes
|
// Handle playlist changes - optimized for immediate response
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (previousPlaylistRef.current !== playlistName) {
|
if (previousPlaylistRef.current !== playlistName) {
|
||||||
// Update refs
|
// Update refs immediately
|
||||||
currentPlaylistRef.current = playlistName;
|
currentPlaylistRef.current = playlistName;
|
||||||
currentSearchQueryRef.current = searchQuery;
|
currentSearchQueryRef.current = searchQuery;
|
||||||
previousPlaylistRef.current = playlistName;
|
previousPlaylistRef.current = playlistName;
|
||||||
|
|
||||||
// Clear songs for new playlist to replace them
|
// Batch all state updates together to reduce re-renders
|
||||||
|
React.startTransition(() => {
|
||||||
setSongs([]);
|
setSongs([]);
|
||||||
setHasMore(true);
|
setHasMore(true);
|
||||||
setCurrentPage(1);
|
setCurrentPage(1);
|
||||||
setSearchQuery(initialSearch);
|
setSearchQuery(initialSearch);
|
||||||
setError(null);
|
setError(null);
|
||||||
// Load immediately without setTimeout
|
});
|
||||||
|
|
||||||
|
// Load immediately
|
||||||
loadPage(1, initialSearch, playlistName);
|
loadPage(1, initialSearch, playlistName);
|
||||||
}
|
}
|
||||||
}, [playlistName, initialSearch, loadPage]);
|
}, [playlistName, initialSearch, loadPage]);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user