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:
45
src/hooks/useImageStatus.ts
Normal file
45
src/hooks/useImageStatus.ts
Normal 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 };
|
||||
}
|
||||
Reference in New Issue
Block a user