perf: Optimize playlist manager to fix 727ms click handler delay - Memoize button styles to prevent object recreation on every render - Wrap PlaylistItem in React.memo to prevent unnecessary re-renders - Fixes React violation 'click' handler took 727ms - Should dramatically improve playlist switching responsiveness

This commit is contained in:
Geert Rademakes 2025-08-06 10:52:11 +02:00
parent 586b3634b5
commit 510c6e1026

View File

@ -36,27 +36,50 @@ interface PlaylistManagerProps {
onPlaylistMove: (playlistName: string, targetFolderName: string | null) => void; onPlaylistMove: (playlistName: string, targetFolderName: string | null) => void;
} }
const getButtonStyles = (isSelected: boolean) => ({ // Memoized button styles to prevent unnecessary re-renders
const selectedButtonStyles = {
width: "100%", width: "100%",
display: "flex", display: "flex",
alignItems: "center", alignItems: "center",
justifyContent: "space-between", justifyContent: "space-between",
bg: isSelected ? "blue.800" : "transparent", bg: "blue.800",
color: isSelected ? "white" : "gray.100", color: "white",
fontWeight: isSelected ? "600" : "normal", fontWeight: "600",
borderRadius: "md", borderRadius: "md",
px: 4, px: 4,
py: 2, py: 2,
cursor: "pointer", cursor: "pointer",
transition: "all 0.2s", transition: "all 0.2s",
_hover: { _hover: {
bg: isSelected ? "blue.600" : "whiteAlpha.200", bg: "blue.600",
transform: "translateX(2px)", transform: "translateX(2px)",
}, },
_active: { _active: {
bg: isSelected ? "blue.700" : "whiteAlpha.300", bg: "blue.700",
}, },
}); };
const unselectedButtonStyles = {
width: "100%",
display: "flex",
alignItems: "center",
justifyContent: "space-between",
bg: "transparent",
color: "gray.100",
fontWeight: "normal",
borderRadius: "md",
px: 4,
py: 2,
cursor: "pointer",
transition: "all 0.2s",
_hover: {
bg: "whiteAlpha.200",
transform: "translateX(2px)",
},
_active: {
bg: "whiteAlpha.300",
},
};
interface PlaylistItemProps { interface PlaylistItemProps {
node: PlaylistNode; node: PlaylistNode;
@ -68,7 +91,7 @@ interface PlaylistItemProps {
allFolders: { name: string }[]; allFolders: { name: string }[];
} }
const PlaylistItem: React.FC<PlaylistItemProps> = ({ const PlaylistItem: React.FC<PlaylistItemProps> = React.memo(({
node, node,
level, level,
selectedItem, selectedItem,
@ -86,7 +109,7 @@ const PlaylistItem: React.FC<PlaylistItemProps> = ({
<Flex align="center" gap={1}> <Flex align="center" gap={1}>
<Button <Button
flex={1} flex={1}
{...getButtonStyles(false)} {...unselectedButtonStyles}
onClick={() => setIsOpen(!isOpen)} onClick={() => setIsOpen(!isOpen)}
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
@ -154,7 +177,7 @@ const PlaylistItem: React.FC<PlaylistItemProps> = ({
<Flex align="center" gap={0}> <Flex align="center" gap={0}>
<Button <Button
flex="1 1 auto" flex="1 1 auto"
{...getButtonStyles(selectedItem === node.name)} {...(selectedItem === node.name ? selectedButtonStyles : unselectedButtonStyles)}
onClick={() => onPlaylistSelect(node.name)} onClick={() => onPlaylistSelect(node.name)}
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
@ -237,7 +260,7 @@ const PlaylistItem: React.FC<PlaylistItemProps> = ({
</Menu> </Menu>
</Flex> </Flex>
); );
}; });
export const PlaylistManager: React.FC<PlaylistManagerProps> = ({ export const PlaylistManager: React.FC<PlaylistManagerProps> = ({
playlists, playlists,
@ -289,7 +312,7 @@ export const PlaylistManager: React.FC<PlaylistManagerProps> = ({
<Box> <Box>
<VStack spacing={2} align="stretch" mb={4}> <VStack spacing={2} align="stretch" mb={4}>
<Button <Button
{...getButtonStyles(selectedItem === null)} {...(selectedItem === null ? selectedButtonStyles : unselectedButtonStyles)}
onClick={() => onPlaylistSelect(null)} onClick={() => onPlaylistSelect(null)}
> >
All Songs All Songs