feat: Implement useImageStatus hook and enhance image loading status handling across various components to address cached images and loading timeouts.

This commit is contained in:
pradeepkumar
2026-03-18 11:54:40 +05:30
parent f3c4e31924
commit 772e1024cc
17 changed files with 211 additions and 93 deletions

View File

@@ -0,0 +1,45 @@
import { useState, useEffect, useCallback, useRef } from 'react';
/**
* Hook to reliably track image loading status.
* Handles the browser cache race condition where `onLoad` fires
* before React attaches the event handler, leaving images stuck
* in a loading/shimmer state.
*
* Also includes a timeout fallback to prevent infinite loading states.
*/
export function useImageStatus(src: string | null | undefined) {
const [status, setStatus] = useState<'loading' | 'loaded' | 'error'>(
src ? 'loading' : 'error'
);
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
// Reset when src changes
useEffect(() => {
setStatus(src ? 'loading' : 'error');
}, [src]);
// Timeout fallback - if image doesn't load within 15s, mark as error
useEffect(() => {
if (status !== 'loading' || !src) return;
timeoutRef.current = setTimeout(() => {
setStatus((prev) => (prev === 'loading' ? 'error' : prev));
}, 15000);
return () => {
if (timeoutRef.current) clearTimeout(timeoutRef.current);
};
}, [src, status]);
// Ref callback - handles cached images where onLoad may have
// already fired before the handler was attached
const setImgRef = useCallback((el: HTMLImageElement | null) => {
if (el?.complete) {
setStatus(el.naturalWidth > 0 ? 'loaded' : 'error');
}
}, []);
const onLoad = useCallback(() => setStatus('loaded'), []);
const onError = useCallback(() => setStatus('error'), []);
return { status, ref: setImgRef, onLoad, onError };
}