Add auto-retry mechanism for initial post loading

When fewer than 5 posts load on initial page visit, automatically
retry up to 2 times with 800ms delay. Helps with timing issues
where fetch completes before map is ready.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Your Name 2026-02-01 18:45:19 +00:00
parent 53b6426a34
commit 3ee536f24f
1 changed files with 50 additions and 7 deletions

View File

@ -464,12 +464,34 @@ export function usePostsEngine({
const map = mapRef.current; const map = mapRef.current;
if (!map) return; if (!map) return;
initialFetchKickRef.current = true; initialFetchKickRef.current = true;
map.__swForceFetchAt = Date.now();
setTimeout(() => { // Poll until map has valid center, then trigger fetch
let attempts = 0;
const maxAttempts = 20;
const pollInterval = setInterval(() => {
attempts++;
try { try {
const center = map.getCenter();
if (center && center.lat != null && center.lng != null) {
clearInterval(pollInterval);
map.__swForceFetchAt = Date.now();
console.log('[usePostsEngine] Initial fetch kick - map center ready:', center.lat, center.lng);
map.fire("moveend"); map.fire("moveend");
} catch {} } else if (attempts >= maxAttempts) {
}, 120); clearInterval(pollInterval);
// Force it anyway after max attempts
map.__swForceFetchAt = Date.now();
console.log('[usePostsEngine] Initial fetch kick - forcing after max attempts');
map.fire("moveend");
}
} catch (e) {
if (attempts >= maxAttempts) {
clearInterval(pollInterval);
}
}
}, 100);
return () => clearInterval(pollInterval);
}, [mapReady, mapRef]); }, [mapReady, mapRef]);
// CRITICAL: Dedicated effect for contentFilter changes (media filter buttons) // CRITICAL: Dedicated effect for contentFilter changes (media filter buttons)
@ -1234,6 +1256,9 @@ export function usePostsEngine({
} }
try { try {
// Clear initial load flag now that we're actually fetching
initialLoadRef.current = false;
setLoadingPosts(true); setLoadingPosts(true);
setLoadError(""); setLoadError("");
@ -1362,6 +1387,24 @@ export function usePostsEngine({
} }
setLoadingPosts(false); setLoadingPosts(false);
// Auto-retry if we got very few posts (network timing issue)
const MIN_EXPECTED_POSTS = 5;
const fetchedCount = Array.isArray(newPosts) ? newPosts.length : 0;
if (fetchedCount < MIN_EXPECTED_POSTS && initialLoadRef.current) {
const retryKey = `retry:${Math.round(lat * 100)}|${Math.round(lng * 100)}`;
const now = Date.now();
if (retryRef.current.key !== retryKey || now - retryRef.current.ts > 10000) {
retryRef.current = { key: retryKey, count: 0, ts: now };
}
if (retryRef.current.count < 2) {
retryRef.current.count += 1;
retryRef.current.ts = now;
console.log(`[usePostsEngine] Low post count (${fetchedCount}), auto-retry #${retryRef.current.count}`);
if (delayedFetchRef.current) clearTimeout(delayedFetchRef.current);
delayedFetchRef.current = setTimeout(load, 800);
}
}
} catch (err) { } catch (err) {
setLoadingPosts(false); setLoadingPosts(false);
setLoadError("fetch failed"); setLoadError("fetch failed");
@ -1391,8 +1434,8 @@ export function usePostsEngine({
const forceFetchNow = mapObj?.__swForceFetchAt && Date.now() - mapObj.__swForceFetchAt < 5000; const forceFetchNow = mapObj?.__swForceFetchAt && Date.now() - mapObj.__swForceFetchAt < 5000;
if (initialLoadRef.current || forceFetchNow) { if (initialLoadRef.current || forceFetchNow) {
initialLoadRef.current = false; // Don't clear initialLoadRef here - let load() clear it after successful fetch
// Note: flag is cleared inside load() at line ~1095, not here // This way if load() returns early (no view center), we'll retry on next effect run
load(); // Immediate fetch for initial load or filter change load(); // Immediate fetch for initial load or filter change
} else { } else {
moveDebounceRef.current = setTimeout(load, 300); moveDebounceRef.current = setTimeout(load, 300);