mmy / hooks /useAssetLoader.ts
Mohammad Shahid
first commit
3a7a84c
// src/hooks/useAssetLoader.ts
import { useState, useEffect } from 'react';
// Defines the structure for our asset map
export type AssetSource = {
id: string;
label: string;
src: string;
};
// The hook returns the loaded images and the loading status
export const useAssetLoader = (assets: AssetSource[]) => {
const [loadedImages, setLoadedImages] = useState<
Record<string, HTMLImageElement>
>({});
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
// Reset state when assets change
setIsLoading(true);
setLoadedImages({});
setError(null);
if (assets.length === 0) {
setIsLoading(false);
return;
}
const loadImages = async () => {
try {
const promises = assets.map((asset) => {
return new Promise<void>((resolve, reject) => {
const img = new Image();
// --- THIS IS THE CRITICAL FIX ---
// This attribute tells the browser it's okay to use this cross-origin image on a canvas
// that you intend to capture a stream from.
img.crossOrigin = "anonymous";
// --------------------------------
img.src = asset.src;
img.onload = () => {
setLoadedImages((prev) => ({ ...prev, [asset.id]: img }));
resolve();
};
img.onerror = (err) => {
console.error(
`Failed to load asset: ${asset.label} from ${asset.src}`,
err
);
reject(new Error(`Failed to load ${asset.label}`));
};
});
});
await Promise.all(promises);
} catch (err: unknown) {
console.error("Failed to load one or more assets:", err);
if (err instanceof Error) {
setError(err.message);
} else {
setError("An unknown error occurred during asset loading.");
}
} finally {
setIsLoading(false);
}
};
loadImages();
}, [JSON.stringify(assets)]); // Use stringify to deep-compare the assets array dependency
return { loadedImages, isLoading, error };
};