retry camera snapshots after a failed load

AutoUpdatingCameraImage only scheduled the next frame from onLoad, so a single failed latest.webp request froze the image until the component remounted. It now retries on error, dropping the periodic cache key so the retry requests a fresh URL.
This commit is contained in:
Josh Hawkins
2026-10-22 16:54:46 -05:00
parent e347a72918
commit 2f33e6e18f
2 changed files with 23 additions and 0 deletions
@@ -12,6 +12,7 @@ type AutoUpdatingCameraImageProps = {
};
const MIN_LOAD_TIMEOUT_MS = 200;
const ERROR_RETRY_MS = 1000;
export default function AutoUpdatingCameraImage({
camera,
@@ -68,6 +69,24 @@ export default function AutoUpdatingCameraImage({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [key, setFps]);
const handleError = useCallback(() => {
if (reloadInterval == -1) {
return;
}
// the periodic cache url doesn't change between retries, so drop it
setIsCached(true);
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
timeoutRef.current = setTimeout(
() => setKey(Date.now()),
Math.max(reloadInterval, ERROR_RETRY_MS),
);
}, [reloadInterval]);
// periodic cache to reduce loading indicator
const [isCached, setIsCached] = useState(false);
@@ -92,6 +111,7 @@ export default function AutoUpdatingCameraImage({
<CameraImage
camera={camera}
onload={handleLoad}
onerror={handleError}
searchParams={cacheKey}
className={cameraClasses}
/>
@@ -11,6 +11,7 @@ type CameraImageProps = {
className?: string;
camera: string;
onload?: () => void;
onerror?: () => void;
searchParams?: string;
};
@@ -18,6 +19,7 @@ export default function CameraImage({
className,
camera,
onload,
onerror,
searchParams = "",
}: CameraImageProps) {
const { data: config } = useSWR("config");
@@ -96,6 +98,7 @@ export default function CameraImage({
"rounded-lg md:rounded-2xl",
)}
onLoad={handleImageLoad}
onError={onerror}
loading="lazy"
/>
) : (