reload by changing the src

Three versions of this now, and the reasons are worth keeping.

key={reloadToken} replaced the ELEMENT, so the panel went white between
documents. contentWindow.location.reload() kept the element but did not reliably
re-fetch. A changing src does both: the browser navigates the same element — so
it keeps painting the current document until the next commits — and the URL
differs, so nothing is served from cache.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-01 21:47:13 +01:00
co-authored by Claude Opus 5
parent 2b2aacca14
commit 26e87df6e5
+11 -19
View File
@@ -227,29 +227,21 @@ export const SitePreview = ({
}, [reloadToken, changed]);
/*
Reload by NAVIGATING the frame, not by replacing it.
Reloading, as a URL.
The frame used to carry `key={reloadToken}`, so a reload was a new element: React unmounted the old
one and the panel went white until the new document arrived. On a page whose crop has just changed
that is not instant — the site is asking av-club for a fresh ladder — so every framing adjustment
flashed an empty panel for a second or two, which reads as the preview breaking.
Three versions of this, and the reasons are worth keeping.
A browser keeps painting the current document while the next one is being fetched. So the same
element stays, and the old page is on screen until the new one commits.
`key={reloadToken}` replaced the ELEMENT, so React unmounted the old frame and the panel went white
until the next document arrived — a second or two after a crop change, because the site is building
a fresh ladder. That reads as the preview breaking.
Same origin, through the dev proxy, which is what makes `contentWindow` reachable at all.
`contentWindow.location.reload()` kept the element but did not reliably re-fetch.
Skipped on the first run: the element has only just mounted and is already loading its document.
A changing `src` does both: the browser navigates the SAME element, so it keeps painting the current
document until the next one commits, and the URL is different so nothing is served from cache. The
parameter means nothing to the site and is ignored.
*/
const first = useRef(true);
useEffect(() => {
if (first.current) {
first.current = false;
return;
}
frame.current?.contentWindow?.location.reload();
}, [reloadToken, changed]);
const reloadKey = `${reloadToken ?? 0}.${changed}`;
useEffect(() => {
if (!loaded) return;
@@ -379,7 +371,7 @@ export const SitePreview = ({
applyTheme();
setLoaded((n) => n + 1);
}}
src={`/api/dev-proxy/${port}/${path}`}
src={`/api/dev-proxy/${port}/${path}?_=${reloadKey}`}
title={`The site at /${path}`}
className="border-0"
// The device's real width, and the room's real height. No transform: see the note above.