fix(artist): decouple artist info fetch from main render path (fix #132)

getArtistInfo2.view can trigger Navidrome to do slow external lookups
(Last.fm / Apple Music) when no local artist image exists, blocking the
entire page for 10+ seconds.

Render the page immediately after getArtist() resolves (local data only),
then fire getArtistInfo and getTopSongs in the background. A cancelled
flag prevents stale state updates when the user navigates away before
either background fetch completes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Psychotoxical
2026-04-08 13:10:01 +02:00
parent d6546e12ca
commit c7adb599ee
+17 -9
View File
@@ -80,24 +80,32 @@ export default function ArtistDetail() {
useEffect(() => {
if (!id) return;
let cancelled = false;
setLoading(true);
setInfo(null);
setTopSongs([]);
setFeaturedAlbums([]);
getArtist(id).then(artistData => {
if (cancelled) return;
setArtist(artistData.artist);
setAlbums(artistData.albums);
setIsStarred(!!artistData.artist.starred);
return Promise.all([
getArtistInfo(id).catch(() => null),
getTopSongs(artistData.artist.name).catch(() => []),
]);
}).then(([artistInfo, songsData]) => {
if (artistInfo !== undefined) setInfo(artistInfo as SubsonicArtistInfo | null);
if (songsData !== undefined) setTopSongs(songsData as SubsonicSong[]);
// Render the page immediately from local data
setLoading(false);
// Fetch artist info (may trigger slow external lookup on the server)
// and top songs in the background — do not block rendering
getArtistInfo(id).then(artistInfo => {
if (!cancelled) setInfo(artistInfo ?? null);
}).catch(() => {});
getTopSongs(artistData.artist.name).then(songsData => {
if (!cancelled) setTopSongs(songsData ?? []);
}).catch(() => {});
}).catch(err => {
console.error(err);
setLoading(false);
if (!cancelled) { console.error(err); setLoading(false); }
});
return () => { cancelled = true; };
}, [id]);
useEffect(() => {