fix: address code review issues in useUrlImport hook

This commit is contained in:
SnapOtter
2026-05-11 21:34:43 +08:00
parent b7af25862a
commit c901e29528
+22 -17
View File
@@ -81,8 +81,8 @@ export function useUrlImport() {
}, []); }, []);
const downloadAsFile = useCallback( const downloadAsFile = useCallback(
async (downloadUrl: string, filename: string): Promise<File> => { async (downloadUrl: string, filename: string, signal?: AbortSignal): Promise<File> => {
const res = await fetch(downloadUrl, { headers: formatHeaders() }); const res = await fetch(downloadUrl, { headers: formatHeaders(), signal });
if (!res.ok) throw new Error(`Download failed: ${res.status}`); if (!res.ok) throw new Error(`Download failed: ${res.status}`);
const blob = await res.blob(); const blob = await res.blob();
return new File([blob], filename, { type: blob.type }); return new File([blob], filename, { type: blob.type });
@@ -130,11 +130,13 @@ export function useUrlImport() {
const importSingleUrl = useCallback( const importSingleUrl = useCallback(
async (url: string): Promise<File | null> => { async (url: string): Promise<File | null> => {
const controller = new AbortController();
abortRef.current = controller;
try { try {
const { results } = await fetchUrls([url]); const { results } = await fetchUrls([url], controller.signal);
const result = results[0]; const result = results[0];
if (!result?.success || !result.downloadUrl || !result.filename) return null; if (!result?.success || !result.downloadUrl || !result.filename) return null;
return await downloadAsFile(result.downloadUrl, result.filename); return await downloadAsFile(result.downloadUrl, result.filename, controller.signal);
} catch { } catch {
return null; return null;
} }
@@ -148,24 +150,29 @@ export function useUrlImport() {
e.status === "ready" && !!e.downloadUrl && !!e.filename, e.status === "ready" && !!e.downloadUrl && !!e.filename,
); );
const files = await Promise.all(ready.map((e) => downloadAsFile(e.downloadUrl, e.filename))); const settled = await Promise.allSettled(
ready.map((e) => downloadAsFile(e.downloadUrl, e.filename)),
);
return files; return settled
.filter((r): r is PromiseFulfilledResult<File> => r.status === "fulfilled")
.map((r) => r.value);
}, [entries, downloadAsFile]); }, [entries, downloadAsFile]);
const retryUrl = useCallback( const retryUrl = useCallback(
async (index: number) => { async (index: number) => {
const entry = entries[index]; let url: string | undefined;
if (!entry) return; setEntries((prev) => {
url = prev[index]?.url;
setEntries((prev) => if (!url) return prev;
prev.map((e, i) => return prev.map((e, i) =>
i === index ? { ...e, status: "fetching" as const, error: undefined } : e, i === index ? { ...e, status: "fetching" as const, error: undefined } : e,
), );
); });
if (!url) return;
try { try {
const { results } = await fetchUrls([entry.url]); const { results } = await fetchUrls([url]);
const result = results[0]; const result = results[0];
if (!result) return; if (!result) return;
@@ -178,7 +185,7 @@ export function useUrlImport() {
); );
} }
}, },
[entries, fetchUrls, resultToEntry], [fetchUrls, resultToEntry],
); );
const cancel = useCallback(() => { const cancel = useCallback(() => {
@@ -189,8 +196,6 @@ export function useUrlImport() {
}, []); }, []);
const reset = useCallback(() => { const reset = useCallback(() => {
abortRef.current?.abort();
abortRef.current = null;
setEntries([]); setEntries([]);
setImporting(false); setImporting(false);
}, []); }, []);