the preview hung on "Connecting…"
`useClient()` rebuilds its verbs on every render, so `get` has a new identity each time. It was in the effect's dependency list, so the effect re-ran on every render — and its first act is setReady(false), which renders again, which builds another `get`, which re-runs the effect. The frame never mounted. Through a ref instead, with the effect depending only on the port. This trap is documented in CLAUDE.md and it is the same one that silently disabled every playback report in the Jellyfin player. The platform's own Preview panel sidesteps it by depending on neither the client nor the URL, which is what this now does. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -490,7 +490,21 @@ const LinkRow = ({
|
||||
* says so in its own comments.
|
||||
*/
|
||||
const LayoutPreview = ({ port }: { port: number | null }) => {
|
||||
const { get } = useClient();
|
||||
const client = useClient();
|
||||
/*
|
||||
Through a ref, and this is the whole reason the preview hung.
|
||||
|
||||
`useClient()` rebuilds its verbs on EVERY render, so `get` has a new identity each time. With it in
|
||||
the dependency list the effect re-ran on every render, and its first act is `setReady(false)` —
|
||||
which renders again, which makes another `get`, which re-runs the effect. The frame never mounted
|
||||
and the panel said "Connecting…" forever.
|
||||
|
||||
It is a known trap here: the same thing silently disabled every playback report in the Jellyfin
|
||||
player. The platform's own Preview panel avoids it by depending on neither the client nor the URL.
|
||||
*/
|
||||
const clientRef = useRef(client);
|
||||
clientRef.current = client;
|
||||
|
||||
const [ready, setReady] = useState(false);
|
||||
const [failed, setFailed] = useState<string | null>(null);
|
||||
|
||||
@@ -499,13 +513,14 @@ const LayoutPreview = ({ port }: { port: number | null }) => {
|
||||
let alive = true;
|
||||
setReady(false);
|
||||
setFailed(null);
|
||||
void get<{ ok: boolean }>('/dev-proxy/session')
|
||||
void clientRef.current
|
||||
.get<{ ok: boolean }>('/dev-proxy/session')
|
||||
.then(() => alive && setReady(true))
|
||||
.catch((failure: unknown) => alive && setFailed(readableError(failure)));
|
||||
return () => {
|
||||
alive = false;
|
||||
};
|
||||
}, [port, get]);
|
||||
}, [port]);
|
||||
|
||||
const message =
|
||||
!port ? 'No development server is configured — set its port under Administration.'
|
||||
|
||||
Reference in New Issue
Block a user