perf(scan): replace deep watch with computed to reduce reactivity overhead

During a scan with large collections, the scan page becomes slow or
unresponsive. The watch on scanningPlatforms with { deep: true } was
firing on every ROM addition, causing Vue to deeply traverse all nested
platform and ROM data each time.

The watch's only job is deciding which panels are open. A panel should
open when a platform first receives ROMs — after that, its open/closed
state doesn't need to change regardless of how many more ROMs arrive.

Replace with a computed that maps each platform to a boolean
(roms.length > 0), so the watch only fires on that one meaningful
transition per platform. The ROM list inside each panel continues to
update reactively as normal — this change only affects the panel
open/close logic.

Note: This PR was written with AI assistance (Claude Code).
This commit is contained in:
cc
2026-03-09 20:32:04 -04:00
parent da09f6c81c
commit 6936a089b8

View File

@@ -90,16 +90,18 @@ watch(metadataOptions, (newOptions) => {
);
});
// Adding each new scanned platform to panelIndex to be open by default
watch(
scanningPlatforms,
() => {
panels.value = scanningPlatforms.value
.map((p, index) => (p.roms.length > 0 ? index : -1))
.filter((index) => index !== -1);
},
{ deep: true },
// Track which platforms have ROMs without a deep watch on the entire array.
// The computed returns a stable string that only changes when a platform
// transitions from 0→>0 ROMs (or back), so the watch fires O(n_platforms)
// times rather than O(n_roms) times.
const platformsWithRomsKey = computed(() =>
scanningPlatforms.value.map((p) => (p.roms.length > 0 ? 1 : 0)).join(""),
);
watch(platformsWithRomsKey, () => {
panels.value = scanningPlatforms.value
.map((p, index) => (p.roms.length > 0 ? index : -1))
.filter((index) => index !== -1);
});
const scanOptions = [
{