Update use-directories.ts

This commit is contained in:
plebeius
2026-02-15 14:40:48 +08:00
parent e47727c074
commit 32bf635a3c
+97 -179
View File
@@ -35,6 +35,7 @@ const CACHE_MAX_AGE_MS = 60 * 60 * 1000; // 1 hour
let cacheCommunities: DirectoryCommunity[] | null = null; let cacheCommunities: DirectoryCommunity[] | null = null;
let cacheMetadata: DirectoriesMetadata | null = null; let cacheMetadata: DirectoriesMetadata | null = null;
let inFlightGitHubFetch: Promise<DirectoriesData> | null = null;
const getFromLocalStorage = (): DirectoriesData | null => { const getFromLocalStorage = (): DirectoriesData | null => {
try { try {
@@ -61,21 +62,24 @@ const saveToLocalStorage = (data: DirectoriesData) => {
} }
}; };
const fetchDirectoriesData = async (): Promise<DirectoriesData> => { const fetchDirectoriesFromGitHub = async (): Promise<DirectoriesData> => {
try { const response = await fetch(GITHUB_URL, { cache: 'no-cache' });
const response = await fetch(GITHUB_URL); if (!response.ok) {
if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`);
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
// Save successful fetch to localStorage
saveToLocalStorage(data);
return data;
} catch (e) {
console.warn('Failed to fetch directories from GitHub, using vendored fallback:', e);
// Fall back to vendored file
return directoriesData as DirectoriesData;
} }
const data = await response.json();
// Save successful fetch to localStorage
saveToLocalStorage(data);
return data;
};
const fetchDirectoriesFromGitHubDeduped = async (): Promise<DirectoriesData> => {
if (!inFlightGitHubFetch) {
inFlightGitHubFetch = fetchDirectoriesFromGitHub().finally(() => {
inFlightGitHubFetch = null;
});
}
return inFlightGitHubFetch;
}; };
export const useDirectories = () => { export const useDirectories = () => {
@@ -88,69 +92,42 @@ export const useDirectories = () => {
}); });
useEffect(() => { useEffect(() => {
if (cacheCommunities) {
setState({
communities: cacheCommunities,
loading: false,
error: null,
});
return;
}
let isMounted = true; let isMounted = true;
const hydrateCommunities = (data: DirectoriesData) => {
cacheCommunities = data.communities;
if (isMounted) {
setState({
communities: data.communities,
loading: false,
error: null,
});
}
};
(async () => { (async () => {
try { if (cacheCommunities) {
setState({
communities: cacheCommunities,
loading: false,
error: null,
});
} else {
// Check localStorage first // Check localStorage first
const cachedData = getFromLocalStorage(); const cachedData = getFromLocalStorage();
if (cachedData) { if (cachedData) {
cacheCommunities = cachedData.communities; hydrateCommunities(cachedData);
if (isMounted) {
setState({
communities: cachedData.communities,
loading: false,
error: null,
});
}
// Still try to fetch fresh data in background (don't await)
fetchDirectoriesData()
.then((data) => {
if (isMounted) {
cacheCommunities = data.communities;
setState({
communities: data.communities,
loading: false,
error: null,
});
}
})
.catch((e) => {
console.warn('Background fetch failed:', e);
});
return;
} }
}
// No cache, fetch fresh data try {
const directories = await fetchDirectoriesData(); // Always attempt a background refresh from GitHub to pick up list updates
if (isMounted) { const directories = await fetchDirectoriesFromGitHubDeduped();
cacheCommunities = directories.communities; hydrateCommunities(directories);
setState({
communities: directories.communities,
loading: false,
error: null,
});
}
} catch (e) { } catch (e) {
console.warn('Failed to load directories:', e); console.warn('Failed to fetch directories from GitHub:', e);
// Fallback to vendored data // Only fall back if we don't already have memory/localStorage data
const fallbackData = directoriesData as DirectoriesData; if (!cacheCommunities) {
if (isMounted) { hydrateCommunities(directoriesData as DirectoriesData);
cacheCommunities = fallbackData.communities;
setState({
communities: fallbackData.communities,
loading: false,
error: null,
});
} }
} }
})(); })();
@@ -175,69 +152,42 @@ export const useDirectoriesState = () => {
}); });
useEffect(() => { useEffect(() => {
if (cacheCommunities) {
setState({
communities: cacheCommunities,
loading: false,
error: null,
});
return;
}
let isMounted = true; let isMounted = true;
const hydrateCommunities = (data: DirectoriesData) => {
cacheCommunities = data.communities;
if (isMounted) {
setState({
communities: data.communities,
loading: false,
error: null,
});
}
};
(async () => { (async () => {
try { if (cacheCommunities) {
setState({
communities: cacheCommunities,
loading: false,
error: null,
});
} else {
// Check localStorage first // Check localStorage first
const cachedData = getFromLocalStorage(); const cachedData = getFromLocalStorage();
if (cachedData) { if (cachedData) {
cacheCommunities = cachedData.communities; hydrateCommunities(cachedData);
if (isMounted) {
setState({
communities: cachedData.communities,
loading: false,
error: null,
});
}
// Still try to fetch fresh data in background (don't await)
fetchDirectoriesData()
.then((data) => {
if (isMounted) {
cacheCommunities = data.communities;
setState({
communities: data.communities,
loading: false,
error: null,
});
}
})
.catch((e) => {
console.warn('Background fetch failed:', e);
});
return;
} }
}
// No cache, fetch fresh data try {
const directories = await fetchDirectoriesData(); // Always attempt a background refresh from GitHub to pick up list updates
if (isMounted) { const directories = await fetchDirectoriesFromGitHubDeduped();
cacheCommunities = directories.communities; hydrateCommunities(directories);
setState({
communities: directories.communities,
loading: false,
error: null,
});
}
} catch (e) { } catch (e) {
console.warn('Failed to load directories:', e); console.warn('Failed to fetch directories from GitHub:', e);
// Fallback to vendored data // Only fall back if we don't already have memory/localStorage data
const fallbackData = directoriesData as DirectoriesData; if (!cacheCommunities) {
if (isMounted) { hydrateCommunities(directoriesData as DirectoriesData);
cacheCommunities = fallbackData.communities;
setState({
communities: fallbackData.communities,
loading: false,
error: null,
});
} }
} }
})(); })();
@@ -259,72 +209,40 @@ export const useDirectoriesMetadata = () => {
const [metadata, setMetadata] = useState<DirectoriesMetadata | null>(null); const [metadata, setMetadata] = useState<DirectoriesMetadata | null>(null);
useEffect(() => { useEffect(() => {
if (cacheMetadata) {
return;
}
let isMounted = true; let isMounted = true;
const hydrateMetadata = (data: DirectoriesData) => {
const nextMetadata: DirectoriesMetadata = {
title: data.title,
description: data.description,
createdAt: data.createdAt,
updatedAt: data.updatedAt,
};
cacheMetadata = nextMetadata;
if (isMounted) {
setMetadata(nextMetadata);
}
};
(async () => { (async () => {
try { if (cacheMetadata) {
setMetadata(cacheMetadata);
} else {
// Check localStorage first // Check localStorage first
const cachedData = getFromLocalStorage(); const cachedData = getFromLocalStorage();
if (cachedData) { if (cachedData) {
const metadata: DirectoriesMetadata = { hydrateMetadata(cachedData);
title: cachedData.title,
description: cachedData.description,
createdAt: cachedData.createdAt,
updatedAt: cachedData.updatedAt,
};
cacheMetadata = metadata;
if (isMounted) {
setMetadata(metadata);
}
// Still try to fetch fresh data in background (don't await)
fetchDirectoriesData()
.then((data) => {
if (isMounted) {
const freshMetadata: DirectoriesMetadata = {
title: data.title,
description: data.description,
createdAt: data.createdAt,
updatedAt: data.updatedAt,
};
cacheMetadata = freshMetadata;
setMetadata(freshMetadata);
}
})
.catch((e) => {
console.warn('Background metadata fetch failed:', e);
});
return;
} }
}
// No cache, fetch fresh data try {
const directories = await fetchDirectoriesData(); // Always attempt a background refresh from GitHub to pick up metadata updates
if (isMounted) { const directories = await fetchDirectoriesFromGitHubDeduped();
const metadata: DirectoriesMetadata = { hydrateMetadata(directories);
title: directories.title,
description: directories.description,
createdAt: directories.createdAt,
updatedAt: directories.updatedAt,
};
cacheMetadata = metadata;
setMetadata(metadata);
}
} catch (e) { } catch (e) {
console.warn('Failed to load metadata, using vendored fallback:', e); console.warn('Failed to fetch directory metadata from GitHub:', e);
// Fallback to vendored data // Only fall back if we don't already have memory/localStorage data
const fallbackData = directoriesData as DirectoriesData; if (!cacheMetadata) {
if (isMounted) { hydrateMetadata(directoriesData as DirectoriesData);
const metadata: DirectoriesMetadata = {
title: fallbackData.title,
description: fallbackData.description,
createdAt: fallbackData.createdAt,
updatedAt: fallbackData.updatedAt,
};
cacheMetadata = metadata;
setMetadata(metadata);
} }
} }
})(); })();