From 231de978e18d765e0e5ecab183420a188e349a0b Mon Sep 17 00:00:00 2001 From: megatwig <137281832+megatwig@users.noreply.github.com> Date: Mon, 20 Apr 2026 06:27:47 +0100 Subject: [PATCH 1/4] Add missing (empty) dependency array to `useEffect()` A `useEffect` without a dependency array is re-evaluated on every single render. Most of these are just binding (and unbinding) keyboard shortcuts, so should be pretty safe to update in bulk. I did spot a couple that skip keybind listeners if `!isVisible`, so set as a dependency so they'll still get installed. --- .../Galleries/GalleryDetails/GalleryChaptersPanel.tsx | 2 +- ui/v2.5/src/components/Galleries/GalleryList.tsx | 2 +- ui/v2.5/src/components/Groups/GroupDetails/Group.tsx | 2 +- ui/v2.5/src/components/Groups/GroupDetails/GroupEditPanel.tsx | 2 +- ui/v2.5/src/components/Groups/GroupList.tsx | 2 +- ui/v2.5/src/components/Images/ImageDetails/Image.tsx | 2 +- ui/v2.5/src/components/Images/ImageDetails/ImageEditPanel.tsx | 2 +- ui/v2.5/src/components/List/EditFilterDialog.tsx | 2 +- ui/v2.5/src/components/List/ListFilter.tsx | 2 +- ui/v2.5/src/components/List/ListViewOptions.tsx | 2 +- ui/v2.5/src/components/List/ZoomSlider.tsx | 2 +- ui/v2.5/src/components/MainNavbar.tsx | 2 +- .../src/components/Performers/PerformerDetails/Performer.tsx | 4 ++-- .../Performers/PerformerDetails/PerformerEditPanel.tsx | 2 +- ui/v2.5/src/components/Performers/PerformerList.tsx | 2 +- ui/v2.5/src/components/Scenes/SceneDetails/Scene.tsx | 2 +- ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx | 2 +- .../src/components/Scenes/SceneDetails/SceneMarkersPanel.tsx | 2 +- ui/v2.5/src/components/Studios/StudioDetails/Studio.tsx | 2 +- .../src/components/Studios/StudioDetails/StudioEditPanel.tsx | 2 +- ui/v2.5/src/components/Studios/StudioList.tsx | 2 +- ui/v2.5/src/components/Tags/TagDetails/Tag.tsx | 2 +- ui/v2.5/src/components/Tags/TagList.tsx | 2 +- ui/v2.5/src/hooks/LocalForage.ts | 2 +- ui/v2.5/src/hooks/keybinds.ts | 2 +- ui/v2.5/src/utils/form.tsx | 2 +- 26 files changed, 27 insertions(+), 27 deletions(-) diff --git a/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryChaptersPanel.tsx b/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryChaptersPanel.tsx index ea970b7ae..7a507175d 100644 --- a/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryChaptersPanel.tsx +++ b/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryChaptersPanel.tsx @@ -30,7 +30,7 @@ export const GalleryChapterPanel: React.FC = ({ return () => { Mousetrap.unbind("n"); }; - }); + }, [isVisible]); function onOpenEditor(chapter?: GQL.GalleryChapterDataFragment) { setIsEditorOpen(true); diff --git a/ui/v2.5/src/components/Galleries/GalleryList.tsx b/ui/v2.5/src/components/Galleries/GalleryList.tsx index abb2bdda8..af905a8f0 100644 --- a/ui/v2.5/src/components/Galleries/GalleryList.tsx +++ b/ui/v2.5/src/components/Galleries/GalleryList.tsx @@ -324,7 +324,7 @@ export const FilteredGalleryList = PatchComponent( Mousetrap.unbind("e"); Mousetrap.unbind("d d"); }; - }); + }, []); const onCloseEditDelete = useCloseEditDelete({ closeModal, diff --git a/ui/v2.5/src/components/Groups/GroupDetails/Group.tsx b/ui/v2.5/src/components/Groups/GroupDetails/Group.tsx index b2b3d8176..bc75539a8 100644 --- a/ui/v2.5/src/components/Groups/GroupDetails/Group.tsx +++ b/ui/v2.5/src/components/Groups/GroupDetails/Group.tsx @@ -243,7 +243,7 @@ const GroupPage: React.FC = ({ group, tabKey }) => { Mousetrap.unbind("e"); Mousetrap.unbind("d d"); }; - }); + }, []); useRatingKeybinds( true, diff --git a/ui/v2.5/src/components/Groups/GroupDetails/GroupEditPanel.tsx b/ui/v2.5/src/components/Groups/GroupDetails/GroupEditPanel.tsx index 6401738fa..7bf884511 100644 --- a/ui/v2.5/src/components/Groups/GroupDetails/GroupEditPanel.tsx +++ b/ui/v2.5/src/components/Groups/GroupDetails/GroupEditPanel.tsx @@ -172,7 +172,7 @@ export const GroupEditPanel: React.FC = ({ // Mousetrap.unbind("u"); Mousetrap.unbind("s s"); }; - }); + }, []); function updateGroupEditStateFromScraper( state: Partial diff --git a/ui/v2.5/src/components/Groups/GroupList.tsx b/ui/v2.5/src/components/Groups/GroupList.tsx index 69961f783..d67b2fcf5 100644 --- a/ui/v2.5/src/components/Groups/GroupList.tsx +++ b/ui/v2.5/src/components/Groups/GroupList.tsx @@ -288,7 +288,7 @@ export const FilteredGroupList = PatchComponent( Mousetrap.unbind("e"); Mousetrap.unbind("d d"); }; - }); + }, []); const onCloseEditDelete = useCloseEditDelete({ closeModal, diff --git a/ui/v2.5/src/components/Images/ImageDetails/Image.tsx b/ui/v2.5/src/components/Images/ImageDetails/Image.tsx index f885c21bb..35e5f50b3 100644 --- a/ui/v2.5/src/components/Images/ImageDetails/Image.tsx +++ b/ui/v2.5/src/components/Images/ImageDetails/Image.tsx @@ -298,7 +298,7 @@ const ImagePage: React.FC = ({ image }) => { Mousetrap.unbind("f"); Mousetrap.unbind("o"); }; - }); + }, []); const file = useMemo( () => (image.visual_files.length > 0 ? image.visual_files[0] : undefined), diff --git a/ui/v2.5/src/components/Images/ImageDetails/ImageEditPanel.tsx b/ui/v2.5/src/components/Images/ImageDetails/ImageEditPanel.tsx index 94dddac4b..cbb587e32 100644 --- a/ui/v2.5/src/components/Images/ImageDetails/ImageEditPanel.tsx +++ b/ui/v2.5/src/components/Images/ImageDetails/ImageEditPanel.tsx @@ -177,7 +177,7 @@ export const ImageEditPanel: React.FC = ({ Mousetrap.unbind("d d"); }; } - }); + }, []); const fragmentScrapers = useMemo(() => { return (scrapers?.data?.listScrapers ?? []).filter((s) => diff --git a/ui/v2.5/src/components/List/EditFilterDialog.tsx b/ui/v2.5/src/components/List/EditFilterDialog.tsx index 3f0f486b8..0a6b3356e 100644 --- a/ui/v2.5/src/components/List/EditFilterDialog.tsx +++ b/ui/v2.5/src/components/List/EditFilterDialog.tsx @@ -359,7 +359,7 @@ export const EditFilterDialog: React.FC = ({ return () => { Mousetrap.unbind("/"); }; - }); + }, []); async function updatePinnedFilters(filters: string[]) { const configKey = filterModeToConfigKey(currentFilter.mode); diff --git a/ui/v2.5/src/components/List/ListFilter.tsx b/ui/v2.5/src/components/List/ListFilter.tsx index ff3be0360..64332461a 100644 --- a/ui/v2.5/src/components/List/ListFilter.tsx +++ b/ui/v2.5/src/components/List/ListFilter.tsx @@ -86,7 +86,7 @@ export const SearchTermInput: React.FC<{ return () => { Mousetrap.unbind("/"); }; - }); + }, []); function onSetQuery(value: string) { setLocalInput(value); diff --git a/ui/v2.5/src/components/List/ListViewOptions.tsx b/ui/v2.5/src/components/List/ListViewOptions.tsx index b681e086d..4c049f2ad 100644 --- a/ui/v2.5/src/components/List/ListViewOptions.tsx +++ b/ui/v2.5/src/components/List/ListViewOptions.tsx @@ -105,7 +105,7 @@ export const ListViewOptions: React.FC = ({ Mousetrap.unbind("v w"); Mousetrap.unbind("v t"); }; - }); + }, []); function onChangeZoom(v: number) { if (onSetZoom) { diff --git a/ui/v2.5/src/components/List/ZoomSlider.tsx b/ui/v2.5/src/components/List/ZoomSlider.tsx index 093b5ec7a..36913fff3 100644 --- a/ui/v2.5/src/components/List/ZoomSlider.tsx +++ b/ui/v2.5/src/components/List/ZoomSlider.tsx @@ -26,7 +26,7 @@ export function useZoomKeybinds(props: { Mousetrap.unbind("+"); Mousetrap.unbind("-"); }; - }); + }, []); } export interface IZoomSelectProps { diff --git a/ui/v2.5/src/components/MainNavbar.tsx b/ui/v2.5/src/components/MainNavbar.tsx index c70994476..57f768f77 100644 --- a/ui/v2.5/src/components/MainNavbar.tsx +++ b/ui/v2.5/src/components/MainNavbar.tsx @@ -276,7 +276,7 @@ export const MainNavbar: React.FC = () => { Mousetrap.unbind("n"); } }; - }); + }, []); function maybeRenderLogout() { if (SessionUtils.isLoggedIn()) { diff --git a/ui/v2.5/src/components/Performers/PerformerDetails/Performer.tsx b/ui/v2.5/src/components/Performers/PerformerDetails/Performer.tsx index 92a563a81..be393bd60 100644 --- a/ui/v2.5/src/components/Performers/PerformerDetails/Performer.tsx +++ b/ui/v2.5/src/components/Performers/PerformerDetails/Performer.tsx @@ -112,7 +112,7 @@ const PerformerTabs: React.FC<{ Mousetrap.unbind("g"); Mousetrap.unbind("m"); }; - }); + }, []); return ( = PatchComponent( Mousetrap.unbind("f"); Mousetrap.unbind(","); }; - }); + }, []); async function onSave(input: GQL.PerformerCreateInput) { await updatePerformer({ diff --git a/ui/v2.5/src/components/Performers/PerformerDetails/PerformerEditPanel.tsx b/ui/v2.5/src/components/Performers/PerformerDetails/PerformerEditPanel.tsx index 6d5570ef0..5f6d866cd 100644 --- a/ui/v2.5/src/components/Performers/PerformerDetails/PerformerEditPanel.tsx +++ b/ui/v2.5/src/components/Performers/PerformerDetails/PerformerEditPanel.tsx @@ -383,7 +383,7 @@ export const PerformerEditPanel: React.FC = ({ } }; } - }); + }, []); useEffect(() => { const newQueryableScrapers = (Scrapers?.data?.listScrapers ?? []).filter( diff --git a/ui/v2.5/src/components/Performers/PerformerList.tsx b/ui/v2.5/src/components/Performers/PerformerList.tsx index c2db288bc..0664c4ab9 100644 --- a/ui/v2.5/src/components/Performers/PerformerList.tsx +++ b/ui/v2.5/src/components/Performers/PerformerList.tsx @@ -447,7 +447,7 @@ export const FilteredPerformerList = PatchComponent( Mousetrap.unbind("e"); Mousetrap.unbind("d d"); }; - }); + }, []); const onCloseEditDelete = useCloseEditDelete({ closeModal, diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/Scene.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/Scene.tsx index 7d1b245fc..3dc433e80 100644 --- a/ui/v2.5/src/components/Scenes/SceneDetails/Scene.tsx +++ b/ui/v2.5/src/components/Scenes/SceneDetails/Scene.tsx @@ -280,7 +280,7 @@ const ScenePage: React.FC = PatchComponent("ScenePage", (props) => { Mousetrap.unbind("c c"); Mousetrap.unbind("c d"); }; - }); + }, []); async function onSave(input: GQL.SceneCreateInput) { await updateScene({ diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx index 41293ff78..3a7550804 100644 --- a/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx +++ b/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx @@ -257,7 +257,7 @@ export const SceneEditPanel: React.FC = ({ Mousetrap.unbind("d d"); }; } - }); + }, []); useEffect(() => { const toFilter = Scrapers?.data?.listScrapers ?? []; diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/SceneMarkersPanel.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/SceneMarkersPanel.tsx index 28a6e4d98..a997ecbec 100644 --- a/ui/v2.5/src/components/Scenes/SceneDetails/SceneMarkersPanel.tsx +++ b/ui/v2.5/src/components/Scenes/SceneDetails/SceneMarkersPanel.tsx @@ -36,7 +36,7 @@ export const SceneMarkersPanel: React.FC = ({ return () => { Mousetrap.unbind("n"); }; - }); + }, []); if (loading) return null; diff --git a/ui/v2.5/src/components/Studios/StudioDetails/Studio.tsx b/ui/v2.5/src/components/Studios/StudioDetails/Studio.tsx index 0096851e2..3f016984c 100644 --- a/ui/v2.5/src/components/Studios/StudioDetails/Studio.tsx +++ b/ui/v2.5/src/components/Studios/StudioDetails/Studio.tsx @@ -354,7 +354,7 @@ const StudioPage: React.FC = ({ studio, tabKey }) => { Mousetrap.unbind(","); Mousetrap.unbind("f"); }; - }); + }, []); useRatingKeybinds( true, diff --git a/ui/v2.5/src/components/Studios/StudioDetails/StudioEditPanel.tsx b/ui/v2.5/src/components/Studios/StudioDetails/StudioEditPanel.tsx index 490f09a55..ad8d830c4 100644 --- a/ui/v2.5/src/components/Studios/StudioDetails/StudioEditPanel.tsx +++ b/ui/v2.5/src/components/Studios/StudioDetails/StudioEditPanel.tsx @@ -147,7 +147,7 @@ export const StudioEditPanel: React.FC = ({ return () => { Mousetrap.unbind("s s"); }; - }); + }, []); async function onSave(input: InputValues, andNew?: boolean) { setIsLoading(true); diff --git a/ui/v2.5/src/components/Studios/StudioList.tsx b/ui/v2.5/src/components/Studios/StudioList.tsx index b75e9782b..24b02d57c 100644 --- a/ui/v2.5/src/components/Studios/StudioList.tsx +++ b/ui/v2.5/src/components/Studios/StudioList.tsx @@ -274,7 +274,7 @@ export const FilteredStudioList = PatchComponent( Mousetrap.unbind("e"); Mousetrap.unbind("d d"); }; - }); + }, []); const onCloseEditDelete = useCloseEditDelete({ closeModal, diff --git a/ui/v2.5/src/components/Tags/TagDetails/Tag.tsx b/ui/v2.5/src/components/Tags/TagDetails/Tag.tsx index 76442b639..61dc5b866 100644 --- a/ui/v2.5/src/components/Tags/TagDetails/Tag.tsx +++ b/ui/v2.5/src/components/Tags/TagDetails/Tag.tsx @@ -359,7 +359,7 @@ const TagPage: React.FC = ({ tag, tabKey }) => { Mousetrap.unbind(","); Mousetrap.unbind("f"); }; - }); + }, []); async function onSave(input: GQL.TagCreateInput) { const oldRelations = { diff --git a/ui/v2.5/src/components/Tags/TagList.tsx b/ui/v2.5/src/components/Tags/TagList.tsx index 5a938bd45..40cd2fb60 100644 --- a/ui/v2.5/src/components/Tags/TagList.tsx +++ b/ui/v2.5/src/components/Tags/TagList.tsx @@ -276,7 +276,7 @@ export const FilteredTagList = PatchComponent( Mousetrap.unbind("e"); Mousetrap.unbind("d d"); }; - }); + }, []); const onCloseEditDelete = useCloseEditDelete({ closeModal, diff --git a/ui/v2.5/src/hooks/LocalForage.ts b/ui/v2.5/src/hooks/LocalForage.ts index cbb1ff64c..2c0183436 100644 --- a/ui/v2.5/src/hooks/LocalForage.ts +++ b/ui/v2.5/src/hooks/LocalForage.ts @@ -83,7 +83,7 @@ export function useLocalForage( }; localForage.setItem(key, Cache[key]); } - }); + }, []); const isLoading = loading || loading === undefined; diff --git a/ui/v2.5/src/hooks/keybinds.ts b/ui/v2.5/src/hooks/keybinds.ts index ac6ab4dd8..9ddf3d863 100644 --- a/ui/v2.5/src/hooks/keybinds.ts +++ b/ui/v2.5/src/hooks/keybinds.ts @@ -81,5 +81,5 @@ export function useRatingKeybinds( return () => { Mousetrap.unbind("r"); }; - }); + }, [isVisible]); } diff --git a/ui/v2.5/src/utils/form.tsx b/ui/v2.5/src/utils/form.tsx index 7c804e221..c5c649c0f 100644 --- a/ui/v2.5/src/utils/form.tsx +++ b/ui/v2.5/src/utils/form.tsx @@ -67,7 +67,7 @@ export function useStopWheelScroll(ref: React.RefObject) { current.removeEventListener("wheel", stopWheelScroll); } }; - }); + }, []); } // NumberField is a wrapper around Form.Control that prevents wheel events from scrolling the window. From 35ca3063d210bed87da50888495b9e7a89393810 Mon Sep 17 00:00:00 2001 From: megatwig <137281832+megatwig@users.noreply.github.com> Date: Mon, 20 Apr 2026 06:55:13 +0100 Subject: [PATCH 2/4] Extra `isVisible` dep --- ui/v2.5/src/components/Images/ImageDetails/ImageEditPanel.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/v2.5/src/components/Images/ImageDetails/ImageEditPanel.tsx b/ui/v2.5/src/components/Images/ImageDetails/ImageEditPanel.tsx index cbb587e32..87e4f85b5 100644 --- a/ui/v2.5/src/components/Images/ImageDetails/ImageEditPanel.tsx +++ b/ui/v2.5/src/components/Images/ImageDetails/ImageEditPanel.tsx @@ -177,7 +177,7 @@ export const ImageEditPanel: React.FC = ({ Mousetrap.unbind("d d"); }; } - }, []); + }, [isVisible]); const fragmentScrapers = useMemo(() => { return (scrapers?.data?.listScrapers ?? []).filter((s) => From 517e5d9a3621d9d5207d6bdb563114808861ab4b Mon Sep 17 00:00:00 2001 From: megatwig <137281832+megatwig@users.noreply.github.com> Date: Mon, 20 Apr 2026 06:57:32 +0100 Subject: [PATCH 3/4] Extra isVisible dep --- .../Performers/PerformerDetails/PerformerEditPanel.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/v2.5/src/components/Performers/PerformerDetails/PerformerEditPanel.tsx b/ui/v2.5/src/components/Performers/PerformerDetails/PerformerEditPanel.tsx index 5f6d866cd..3fc93b58d 100644 --- a/ui/v2.5/src/components/Performers/PerformerDetails/PerformerEditPanel.tsx +++ b/ui/v2.5/src/components/Performers/PerformerDetails/PerformerEditPanel.tsx @@ -383,7 +383,7 @@ export const PerformerEditPanel: React.FC = ({ } }; } - }, []); + }, [isVisible]); useEffect(() => { const newQueryableScrapers = (Scrapers?.data?.listScrapers ?? []).filter( From bf2e2ccedeaa1a7ca87f2b96ee76c2da34d67305 Mon Sep 17 00:00:00 2001 From: megatwig <137281832+megatwig@users.noreply.github.com> Date: Mon, 20 Apr 2026 07:04:16 +0100 Subject: [PATCH 4/4] More `isVisible` deps --- ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx | 2 +- .../src/components/Scenes/SceneDetails/SceneMarkersPanel.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx index 3a7550804..f381d90ab 100644 --- a/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx +++ b/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx @@ -257,7 +257,7 @@ export const SceneEditPanel: React.FC = ({ Mousetrap.unbind("d d"); }; } - }, []); + }, [isVisible]); useEffect(() => { const toFilter = Scrapers?.data?.listScrapers ?? []; diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/SceneMarkersPanel.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/SceneMarkersPanel.tsx index a997ecbec..5c22fdd26 100644 --- a/ui/v2.5/src/components/Scenes/SceneDetails/SceneMarkersPanel.tsx +++ b/ui/v2.5/src/components/Scenes/SceneDetails/SceneMarkersPanel.tsx @@ -36,7 +36,7 @@ export const SceneMarkersPanel: React.FC = ({ return () => { Mousetrap.unbind("n"); }; - }, []); + }, [isVisible]); if (loading) return null;