feat: Add immediate visual feedback for playlist switching - Clear song list immediately when switching playlists for instant feedback - Add 'Switching playlist...' loading indicator with spinner - Set switching state immediately on playlist selection - Reset switching state when new songs are loaded - Makes playlist switching feel much more responsive and clear

This commit is contained in:
Geert Rademakes 2025-08-06 11:12:58 +02:00
parent 4c3b3e31d4
commit 491235af29
3 changed files with 33 additions and 8 deletions

View File

@ -71,6 +71,7 @@ export default function RekordboxReader() {
const { playlists, setPlaylists, loading: xmlLoading } = useXmlParser();
const [selectedSong, setSelectedSong] = useState<Song | null>(null);
const [isDatabaseInitialized, setIsDatabaseInitialized] = useState(false);
const [isSwitchingPlaylist, setIsSwitchingPlaylist] = useState(false);
// Memoized song selection handler to prevent unnecessary re-renders
const handleSongSelect = useCallback((song: Song) => {
@ -153,7 +154,17 @@ export default function RekordboxReader() {
}
}, [currentPlaylist, playlists, navigate, xmlLoading]);
// Reset switching state when songs are loaded
useEffect(() => {
if (songs.length > 0 && isSwitchingPlaylist) {
setIsSwitchingPlaylist(false);
}
}, [songs.length, isSwitchingPlaylist]);
const handlePlaylistSelect = (name: string) => {
// Set switching state immediately for visual feedback
setIsSwitchingPlaylist(true);
// Clear selected song immediately to prevent stale state
setSelectedSong(null);
@ -549,6 +560,7 @@ export default function RekordboxReader() {
onLoadMore={loadNextPage}
onSearch={searchSongs}
searchQuery={searchQuery}
isSwitchingPlaylist={isSwitchingPlaylist}
/>
</Box>

View File

@ -39,6 +39,7 @@ interface PaginatedSongListProps {
onSearch: (query: string) => void;
searchQuery: string;
depth?: number;
isSwitchingPlaylist?: boolean; // New prop to indicate playlist switching
}
// Memoized song item component to prevent unnecessary re-renders
@ -118,7 +119,8 @@ export const PaginatedSongList: React.FC<PaginatedSongListProps> = memo(({
onLoadMore,
onSearch,
searchQuery,
depth = 0
depth = 0,
isSwitchingPlaylist = false
}) => {
const [selectedSongs, setSelectedSongs] = useState<Set<string>>(new Set());
const [localSearchQuery, setLocalSearchQuery] = useState(searchQuery);
@ -427,12 +429,21 @@ export const PaginatedSongList: React.FC<PaginatedSongListProps> = memo(({
</Flex>
)}
{/* No results message */}
{/* No results message or playlist switching indicator */}
{!loading && songs.length === 0 && (
<Flex justify="center" p={8} key="no-results">
<Flex justify="center" p={8} key="no-results" direction="column" align="center" gap={3}>
{isSwitchingPlaylist ? (
<>
<Spinner size="md" color="blue.400" />
<Text color="blue.400" fontSize="sm" fontWeight="medium">
Switching playlist...
</Text>
</>
) : (
<Text color="gray.500">
{searchQuery ? 'No songs found matching your search' : 'No songs available'}
</Text>
)}
</Flex>
)}
</Flex>

View File

@ -146,9 +146,11 @@ export const usePaginatedSongs = (options: UsePaginatedSongsOptions = {}) => {
currentSearchQueryRef.current = searchQuery;
previousPlaylistRef.current = playlistName;
// Batch all state updates together to reduce re-renders
React.startTransition(() => {
// Clear songs IMMEDIATELY for instant visual feedback
setSongs([]);
// Batch remaining state updates together to reduce re-renders
React.startTransition(() => {
setHasMore(true);
setCurrentPage(1);
setSearchQuery(initialSearch);