Browse Source

fix slow-loading profiles

imwald
Silberengel 1 month ago
parent
commit
8f5e140247
  1. 64
      src/hooks/useFetchProfile.tsx

64
src/hooks/useFetchProfile.tsx

@ -442,19 +442,23 @@ export function useFetchProfile(id?: string, skipCache = false) {
} }
} }
// CRITICAL: Early exit if already processing this exact pubkey - prevents infinite loops // Skip only when this pubkey already has an in-flight fetch (global dedupe + local flag).
// This check must happen FIRST, before any other logic // Do **not** return merely because processingPubkeyRef matches: after a failed or timed-out
// Set processingPubkeyRef IMMEDIATELY after extraction to prevent race conditions // fetch, deps can change (e.g. noteFeed.version) while ref is still set — returning here
// left the hook stuck forever (blank profile / 404 until hard reload).
if (extractedPubkey) { if (extractedPubkey) {
if (processingPubkeyRef.current === extractedPubkey) { if (processingPubkeyRef.current === extractedPubkey) {
// Silently exit - no logging to reduce noise const sharedPromise = globalFetchPromises.get(extractedPubkey)
return const busy =
Boolean(sharedPromise) ||
globalFetchingPubkeys.has(extractedPubkey) ||
isFetching
if (busy) return
if (profile?.pubkey === extractedPubkey && !profile.batchPlaceholder) return
} }
// Mark that we're processing this pubkey IMMEDIATELY to prevent concurrent runs
// We'll clear it later if we early exit for other reasons
processingPubkeyRef.current = extractedPubkey processingPubkeyRef.current = extractedPubkey
} }
// CRITICAL: Early exit if we already have a profile for this pubkey // CRITICAL: Early exit if we already have a profile for this pubkey
// This prevents re-fetching when we already have the profile // This prevents re-fetching when we already have the profile
if (extractedPubkey && profile && profile.pubkey === extractedPubkey && !profile.batchPlaceholder) { if (extractedPubkey && profile && profile.pubkey === extractedPubkey && !profile.batchPlaceholder) {
@ -505,6 +509,8 @@ export function useFetchProfile(id?: string, skipCache = false) {
setTimeout(() => { setTimeout(() => {
effectRunCountRef.current.delete(extractedPubkey) effectRunCountRef.current.delete(extractedPubkey)
}, 30000) // Clear after 30 seconds }, 30000) // Clear after 30 seconds
processingPubkeyRef.current = null
if (isFetching) setIsFetching(false)
return return
} }
// Only increment if we're actually going to process // Only increment if we're actually going to process
@ -727,28 +733,28 @@ export function useFetchProfile(id?: string, skipCache = false) {
}, [id, skipCache, noteFeed?.version]) // checkProfile is memoized; noteFeed.version hydrates batch profiles }, [id, skipCache, noteFeed?.version]) // checkProfile is memoized; noteFeed.version hydrates batch profiles
useEffect(() => { useEffect(() => {
// CRITICAL: Only use currentAccountProfile if it matches the pubkey we're looking for const acc = currentAccountProfile
// Use pubkey from the profile object to avoid reference equality issues const accPk = acc?.pubkey
// Only update if we don't have a profile yet AND we're not currently processing if (!accPk || !id) return
// CRITICAL FIX: Don't include profile in dependencies to prevent infinite loops const targetPk = userIdToPubkey(id)
// We only read profile to check if it exists, we don't need to re-run when it changes if (targetPk.length !== 64 || !/^[0-9a-f]{64}$/i.test(targetPk)) return
if (currentAccountProfile?.pubkey && pubkey && pubkey === currentAccountProfile.pubkey) { if (targetPk !== accPk.toLowerCase()) return
// Only update if we don't have a profile yet (avoid unnecessary updates)
// Also check that we're processing this pubkey to prevent race conditions const haveFullLocal =
if (!profile && processingPubkeyRef.current === pubkey) { profile?.pubkey === targetPk && !profile.batchPlaceholder
setProfile(currentAccountProfile) if (haveFullLocal) return
setIsFetching(false)
// Clear interval if we got the profile from current account setProfile(acc)
if (checkIntervalRef.current) { setIsFetching(false)
clearInterval(checkIntervalRef.current) setError(null)
checkIntervalRef.current = null processingPubkeyRef.current = targetPk
} initializedPubkeysRef.current.add(targetPk)
// Clear run count since we have the profile if (checkIntervalRef.current) {
effectRunCountRef.current.delete(pubkey) clearInterval(checkIntervalRef.current)
} checkIntervalRef.current = null
} }
// eslint-disable-next-line react-hooks/exhaustive-deps effectRunCountRef.current.delete(targetPk)
}, [currentAccountProfile?.pubkey, pubkey]) // Removed profile from dependencies to prevent infinite loops }, [currentAccountProfile, id, profile])
return { isFetching, error, profile } return { isFetching, error, profile }
} }

Loading…
Cancel
Save