diff --git a/js/app/hooks/useAvatars.tsx b/js/app/hooks/useAvatars.tsx index c11015e37..4a0f8b487 100644 --- a/js/app/hooks/useAvatars.tsx +++ b/js/app/hooks/useAvatars.tsx @@ -1,5 +1,5 @@ import { ProfileViewDetailed } from "@atproto/api/dist/client/types/app/bsky/actor/defs"; -import { useEffect, useMemo } from "react"; +import { useEffect, useRef } from "react"; import { useStore } from "store"; import { useCachedProfiles } from "store/hooks"; @@ -8,17 +8,21 @@ export default function useAvatars(dids: string[]) { const getProfiles = useStore((state) => state.getProfiles); const profiles: Record = useCachedProfiles(); - const missingDids = useMemo( - () => dids.filter((did) => !(did in profiles)), - [dids, profiles], - ); + // Ask for each DID once. Callers pass a fresh array every render, and a DID + // the Bluesky app view doesn't know (an account on another PDS with no + // Bluesky profile) never lands in the cache, so keying on the array, or + // re-asking for whatever is missing, refetches in a loop. + const requested = useRef(new Set()); + const missing = dids + .filter((did) => !(did in profiles) && !requested.current.has(did)) + .join(","); useEffect(() => { - if (missingDids.length > 0) { - console.log("Fetching profiles for DIDs:", missingDids); - getProfiles(missingDids).then((e) => console.log("ok", e)); - } - }, [missingDids]); + if (!missing) return; + const toFetch = missing.split(","); + toFetch.forEach((did) => requested.current.add(did)); + getProfiles(toFetch); + }, [missing]); return profiles; } diff --git a/js/app/store/slices/blueskySlice.ts b/js/app/store/slices/blueskySlice.ts index 40ee76a7e..d87d9be3d 100644 --- a/js/app/store/slices/blueskySlice.ts +++ b/js/app/store/slices/blueskySlice.ts @@ -450,10 +450,14 @@ export const createBlueskySlice: StateCreator< const bskyAgent = new Agent("https://public.api.bsky.app"); const payload = await bskyAgent.getProfiles({ actors }); let parsedProfiles = {}; - console.log(payload); payload.data.profiles.forEach((p) => { parsedProfiles[p.did] = p; }); + // an unchanged cache must stay the same object, or every subscriber + // re-renders for nothing + if (Object.keys(parsedProfiles).length === 0) { + return; + } set((s) => ({ profileCache: { ...(s as BlueskySlice).profileCache,