Browse Source

reveal avatars

imwald
Silberengel 1 day ago
parent
commit
085e4e57a2
  1. 36
      src/components/UserAvatar/index.tsx
  2. 16
      src/hooks/useFetchProfile.tsx

36
src/components/UserAvatar/index.tsx

@ -163,18 +163,30 @@ function useDeferRemoteProfileAvatar(
setAllowRemote(true) setAllowRemote(true)
return return
} }
const el = containerRef.current let io: IntersectionObserver | null = null
if (!el) return let raf = 0
const io = new IntersectionObserver( const attach = () => {
(entries) => { const el = containerRef.current
if (entries.some((e) => e.isIntersecting)) { if (!el || io) return
setAllowRemote(true) io = new IntersectionObserver(
} (entries) => {
}, if (entries.some((e) => e.isIntersecting)) {
{ root: null, rootMargin: `${AVATAR_VIEWPORT_MARGIN_PX}px`, threshold: 0.01 } setAllowRemote(true)
) }
io.observe(el) },
return () => io.disconnect() { root: null, rootMargin: `${AVATAR_VIEWPORT_MARGIN_PX}px`, threshold: 0.01 }
)
io.observe(el)
}
attach()
// Ref can still be null on the first effect tick (layout ordering); retry once after paint.
if (!containerRef.current) {
raf = window.requestAnimationFrame(() => attach())
}
return () => {
if (raf) cancelAnimationFrame(raf)
io?.disconnect()
}
}, [remoteHttp, allowRemote, containerRef, deferRemote]) }, [remoteHttp, allowRemote, containerRef, deferRemote])
if (sizeBlocked) return fallbackSrc if (sizeBlocked) return fallbackSrc

16
src/hooks/useFetchProfile.tsx

@ -89,9 +89,23 @@ export function useFetchProfile(id?: string, skipCache = false) {
return null return null
} }
// CRITICAL: Check cooldown period first to prevent cascade of duplicate fetches after timeout // CRITICAL: Check cooldown period first to prevent cascade of duplicate fetches after timeout.
// Still hydrate from session/IndexedDB — otherwise new rows remount after a timeout and stay on
// identicons until cooldown ends with no effect re-run (deps unchanged).
const cooldownExpiry = globalFetchCooldowns.get(pubkey) const cooldownExpiry = globalFetchCooldowns.get(pubkey)
if (cooldownExpiry && Date.now() < cooldownExpiry) { if (cooldownExpiry && Date.now() < cooldownExpiry) {
const cachedDuringCooldown = await tryHydrateProfileFromLocalCaches(pubkey, skipCache)
if (!cancelled.current && cachedDuringCooldown) {
setProfile(cachedDuringCooldown)
setIsFetching(false)
initializedPubkeysRef.current.add(pubkey)
if (checkIntervalRef.current) {
clearInterval(checkIntervalRef.current)
checkIntervalRef.current = null
}
effectRunCountRef.current.delete(pubkey)
return cachedDuringCooldown
}
logger.debug('[useFetchProfile] In cooldown period after timeout, skipping fetch', { logger.debug('[useFetchProfile] In cooldown period after timeout, skipping fetch', {
pubkey: pubkey.substring(0, 8), pubkey: pubkey.substring(0, 8),
remainingMs: cooldownExpiry - Date.now() remainingMs: cooldownExpiry - Date.now()

Loading…
Cancel
Save