refactor: hook dependencies name everything the hooks read

The 12 react-hooks/exhaustive-deps warnings the gate let through:
- ShareDialog and YearFilter built a fresh [] per render while their query loaded, so their
  memos recomputed on every render; they share one empty list now.
- VideoEditor's drag effect called a seek/moveBoundary recreated each render; both are stable
  callbacks in its deps.
- WizardProvider re-checks onboarding on exactly the fields it reads (not the me object, whose
  60 s refetch would reopen a closed wizard).
- Channels, Feed and PlexPlayer list the stable values they already used.
- The player's keydown effect is bound once on purpose (its helpers read refs): said so, with a
  disable, as the codebase's other deliberate sites do.
- dialogFocus and the YouTube player's cleanup read refs React may already have let go of; they
  use what they captured when the effect ran.
This commit is contained in:
2026-09-17 02:45:19 +02:00
parent 5883ea509d
commit 569190480d
10 changed files with 66 additions and 32 deletions
+6 -1
View File
@@ -108,6 +108,11 @@ export function useDialogChrome(
// the scope itself, with `focusScope`), so the dialog opens focused rather than stranded on the
// background.
const scope = scopeRef.current;
// The dialog's element as it is while open, for the restore in the CLEANUP — where a closing
// dialog's refs are already detached (refs detach in the commit, passive cleanups run after).
// Today that reads the same either way (a detached owner and a null one both fail every
// `contains` below), but the cleanup should not depend on a ref React has already let go of.
const ownerAtOpen = ownerRef?.current ?? scope;
if (scope && !scope.contains(document.activeElement)) {
const back = focusedRef.current;
const target =
@@ -151,7 +156,7 @@ export function useDialogChrome(
// this, a dialog closing on its own (an in-flight mutation's `onSuccess`) under a modal raised
// above it pulled the focus out of that standing dialog onto our own trigger, behind its
// scrim — where Enter still activated it (deep-review round 7).
const owner = ownerRef?.current ?? scopeRef.current;
const owner = ownerAtOpen;
const active = document.activeElement;
const above = active instanceof Element ? active.closest('[aria-modal="true"]') : null;
const standingAbove =