perf(frontend): use startTransition for selection updates to keep UI responsive on large sets
This commit is contained in:
parent
1d290bdfa6
commit
017ba31d83
@ -1,4 +1,4 @@
|
||||
import React, { useState, useRef, useEffect, useCallback, useMemo, memo } from 'react';
|
||||
import React, { useState, useRef, useEffect, useCallback, useMemo, memo, startTransition } from 'react';
|
||||
import {
|
||||
Box,
|
||||
Flex,
|
||||
@ -224,6 +224,7 @@ export const PaginatedSongList: React.FC<PaginatedSongListProps> = memo(({
|
||||
// const allPlaylists = useMemo(() => getAllPlaylists(playlists), [playlists, getAllPlaylists]);
|
||||
|
||||
const toggleSelection = useCallback((songId: string) => {
|
||||
startTransition(() => {
|
||||
setSelectedSongs(prev => {
|
||||
const newSelection = new Set(prev);
|
||||
if (newSelection.has(songId)) {
|
||||
@ -233,12 +234,14 @@ export const PaginatedSongList: React.FC<PaginatedSongListProps> = memo(({
|
||||
}
|
||||
return newSelection;
|
||||
});
|
||||
});
|
||||
}, []);
|
||||
|
||||
// Range selection using shift-click between last selected and current
|
||||
const toggleSelectionRange = useCallback((fromIndex: number, toIndex: number, checked: boolean) => {
|
||||
if (fromIndex === null || toIndex === null) return;
|
||||
const [start, end] = fromIndex < toIndex ? [fromIndex, toIndex] : [toIndex, fromIndex];
|
||||
startTransition(() => {
|
||||
setSelectedSongs(prev => {
|
||||
const next = new Set(prev);
|
||||
for (let i = start; i <= end; i++) {
|
||||
@ -248,6 +251,7 @@ export const PaginatedSongList: React.FC<PaginatedSongListProps> = memo(({
|
||||
}
|
||||
return next;
|
||||
});
|
||||
});
|
||||
}, [songs]);
|
||||
|
||||
const handleCheckboxToggle = useCallback((index: number, checked: boolean, shift: boolean) => {
|
||||
@ -262,20 +266,19 @@ export const PaginatedSongList: React.FC<PaginatedSongListProps> = memo(({
|
||||
}, [songs, toggleSelection, toggleSelectionRange]);
|
||||
|
||||
const toggleSelectAll = useCallback(() => {
|
||||
startTransition(() => {
|
||||
setSelectedSongs(prev => {
|
||||
const noneSelected = prev.size === 0;
|
||||
const allSelected = prev.size === songs.length && songs.length > 0;
|
||||
if (noneSelected) {
|
||||
// Select all from empty state
|
||||
return new Set(songs.map(s => s.id));
|
||||
}
|
||||
if (allSelected) {
|
||||
// Deselect all when everything is selected
|
||||
return new Set();
|
||||
}
|
||||
// Mixed/some selected: clear first, then select all (single state update reflects final state)
|
||||
return new Set(songs.map(s => s.id));
|
||||
});
|
||||
});
|
||||
}, [songs]);
|
||||
|
||||
const handleBulkAddToPlaylist = useCallback((playlistName: string) => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user