From b0e15935c6645d5e0c6a673054b51809d6023c8c Mon Sep 17 00:00:00 2001 From: jtrzupek Date: Sat, 20 Jun 2026 14:14:07 +0200 Subject: [PATCH] fix(mobile): stop full scene-list refetch on back-navigation (perf) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Returning to the Scenes list from a scene caused a full reload + phone load spike (report 5df48551). Cause: invalidateQueries(['scenes']) in SceneDetail/Player/Performer/Studio handlers — including the silent auto-enrich-thumbnail that fires on opening any thumbnail-less scene — forces react-query to refetch EVERY loaded page of the infinite list. Added refetchType:'none' to all ['scenes'] invalidations: marks stale without refetching the active list, which refreshes on pull-to-refresh / filter change instead. Scene detail (['scene', id]) still updates immediately. Co-Authored-By: Claude Opus 4.8 (1M context) --- mobile/src/changelog.ts | 7 +++++++ mobile/src/screens/PerformerScenesScreen.tsx | 2 +- mobile/src/screens/PlayerScreen.tsx | 5 ++++- mobile/src/screens/SceneDetailScreen.tsx | 10 +++++----- mobile/src/screens/StudioScenesScreen.tsx | 2 +- 5 files changed, 18 insertions(+), 8 deletions(-) diff --git a/mobile/src/changelog.ts b/mobile/src/changelog.ts index febd781..1761bea 100644 --- a/mobile/src/changelog.ts +++ b/mobile/src/changelog.ts @@ -16,6 +16,13 @@ export type ChangelogEntry = { }; export const CHANGELOG: ChangelogEntry[] = [ + { + id: '2026-06-20', + date: 'June 2026', + items: [ + 'Going back to the list from a scene no longer reloads everything or slows the phone.', + ], + }, { id: '2026-06-19', date: 'June 2026', diff --git a/mobile/src/screens/PerformerScenesScreen.tsx b/mobile/src/screens/PerformerScenesScreen.tsx index 2cf1373..6d8d521 100644 --- a/mobile/src/screens/PerformerScenesScreen.tsx +++ b/mobile/src/screens/PerformerScenesScreen.tsx @@ -62,7 +62,7 @@ export function PerformerScenesScreen() { const blacklistMutation = useMutation({ mutationFn: () => client.addBlacklist('performer', id), onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['scenes'] }); + queryClient.invalidateQueries({ queryKey: ['scenes'], refetchType: 'none' }); queryClient.invalidateQueries({ queryKey: ['performer-scenes', id] }); queryClient.invalidateQueries({ queryKey: ['performer-movies', id] }); navigation.goBack(); diff --git a/mobile/src/screens/PlayerScreen.tsx b/mobile/src/screens/PlayerScreen.tsx index d238e33..2cfd2ce 100644 --- a/mobile/src/screens/PlayerScreen.tsx +++ b/mobile/src/screens/PlayerScreen.tsx @@ -69,7 +69,10 @@ function useMarkSourceBroken(params: RouteParams) { await client.markPlaybackDead(params.sceneId, params.playbackId); queryClient.invalidateQueries({ queryKey: ['scene', params.sceneId] }); } - queryClient.invalidateQueries({ queryKey: ['scenes'] }); + // refetchType:'none' — oznacz stale bez wymuszania refetcha całej infinite-listy + // (po powrocie do Scenes powodowało przeładowanie wszystkich stron = obciążenie, + // bug-report 5df48551). Lista odświeży się przy pull-to-refresh / zmianie filtra. + queryClient.invalidateQueries({ queryKey: ['scenes'], refetchType: 'none' }); } catch { // best-effort — i tak wracamy; źródło zostanie do następnej próby } finally { diff --git a/mobile/src/screens/SceneDetailScreen.tsx b/mobile/src/screens/SceneDetailScreen.tsx index a9b9a47..da34bfb 100644 --- a/mobile/src/screens/SceneDetailScreen.tsx +++ b/mobile/src/screens/SceneDetailScreen.tsx @@ -47,7 +47,7 @@ export function SceneDetailScreen() { mutationFn: () => (isFav ? client.removeSceneFavorite(id) : client.addSceneFavorite(id)), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['scene', id] }); - queryClient.invalidateQueries({ queryKey: ['scenes'] }); + queryClient.invalidateQueries({ queryKey: ['scenes'], refetchType: 'none' }); }, }); @@ -105,7 +105,7 @@ export function SceneDetailScreen() { onSuccess: (out) => { if (out.thumbnail_url) { queryClient.invalidateQueries({ queryKey: ['scene', id] }); - queryClient.invalidateQueries({ queryKey: ['scenes'] }); + queryClient.invalidateQueries({ queryKey: ['scenes'], refetchType: 'none' }); } }, }); @@ -126,7 +126,7 @@ export function SceneDetailScreen() { mutationFn: () => client.enrichSceneThumbnail(id, true), onSuccess: (out) => { queryClient.invalidateQueries({ queryKey: ['scene', id] }); - queryClient.invalidateQueries({ queryKey: ['scenes'] }); + queryClient.invalidateQueries({ queryKey: ['scenes'], refetchType: 'none' }); Alert.alert( 'Thumbnail', out.thumbnail_url ? 'Refreshed from the source page.' : 'Could not fetch a fresh thumbnail.', @@ -697,7 +697,7 @@ function PlaybackButton({ 'The tube removed this video. We marked the source, you won\'t see it again.', ); queryClient.invalidateQueries({ queryKey: ['scene', sceneId] }); - queryClient.invalidateQueries({ queryKey: ['scenes'] }); + queryClient.invalidateQueries({ queryKey: ['scenes'], refetchType: 'none' }); return; } // 503 = transient extraction failure (hoster chwilowo niedostępny, network @@ -789,7 +789,7 @@ function PlaybackButton({ try { await client.markPlaybackDead(sceneId, source.id); queryClient.invalidateQueries({ queryKey: ['scene', sceneId] }); - queryClient.invalidateQueries({ queryKey: ['scenes'] }); + queryClient.invalidateQueries({ queryKey: ['scenes'], refetchType: 'none' }); } catch (e) { Alert.alert('Failed', e instanceof Error ? e.message : String(e)); } diff --git a/mobile/src/screens/StudioScenesScreen.tsx b/mobile/src/screens/StudioScenesScreen.tsx index 8894d97..31cb352 100644 --- a/mobile/src/screens/StudioScenesScreen.tsx +++ b/mobile/src/screens/StudioScenesScreen.tsx @@ -55,7 +55,7 @@ export function StudioScenesScreen() { const blacklistMutation = useMutation({ mutationFn: () => client.addBlacklist('studio', studioId), onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['scenes'] }); + queryClient.invalidateQueries({ queryKey: ['scenes'], refetchType: 'none' }); queryClient.invalidateQueries({ queryKey: ['studio-scenes', slug] }); navigation.goBack(); },