Browse Source

fix race condition

imwald
Silberengel 1 month ago
parent
commit
ecc5aab6b2
  1. 37
      src/components/Explore/ExploreRelayReviews.tsx
  2. 7
      src/components/RelayIcon/index.tsx
  3. 2
      src/components/RelayInfo/RelayReviewCard.tsx
  4. 6
      src/hooks/useFetchRelayInfo.tsx

37
src/components/Explore/ExploreRelayReviews.tsx

@ -10,6 +10,7 @@ import { @@ -10,6 +10,7 @@ import {
userReadRelaysWithHttp
} from '@/lib/favorites-feed-relays'
import { toRelay } from '@/lib/link'
import { normalizeAnyRelayUrl } from '@/lib/url'
import { appendCuratedReadOnlyRelays } from '@/pages/primary/SpellsPage/fauxSpellFeeds'
import { useSmartRelayNavigation } from '@/PageManager'
import { useFavoriteRelays } from '@/providers/FavoriteRelaysProvider'
@ -29,7 +30,7 @@ function RelayGroupHeader({ url, reviewCount }: { url: string; reviewCount: numb @@ -29,7 +30,7 @@ function RelayGroupHeader({ url, reviewCount }: { url: string; reviewCount: numb
className="flex w-full min-w-0 items-center gap-2 px-4 md:px-4 pt-4 pb-2 border-b text-left hover:opacity-75 transition-opacity"
onClick={() => navigateToRelay(toRelay(url))}
>
<RelayIcon url={url} className="h-8 w-8 shrink-0 rounded-sm" iconSize={16} />
<RelayIcon url={url} skipRelayInfoFetch className="h-8 w-8 shrink-0 rounded-sm" iconSize={16} />
<div className="min-w-0 flex-1">
{relayInfo?.name && (
<div className="truncate font-semibold text-sm leading-tight">{relayInfo.name}</div>
@ -87,11 +88,35 @@ async function loadCachedRelayReviews(limit: number): Promise<Event[]> { @@ -87,11 +88,35 @@ async function loadCachedRelayReviews(limit: number): Promise<Event[]> {
}
}
function stableRelayInputsKey(
favoriteRelays: string[],
blockedRelays: string[],
relayList: { read?: string[]; write?: string[]; httpRead?: string[] } | null | undefined
): string {
const normSortJoin = (urls: string[]) =>
[...urls]
.map((u) => normalizeAnyRelayUrl(u) || u.trim())
.filter(Boolean)
.sort((a, b) => a.localeCompare(b))
.join('|')
return [
normSortJoin(favoriteRelays),
normSortJoin(blockedRelays),
normSortJoin([...(relayList?.httpRead ?? []), ...(relayList?.read ?? [])]),
normSortJoin(relayList?.write ?? [])
].join('::')
}
export default function ExploreRelayReviews() {
const { t } = useTranslation()
const { favoriteRelays, blockedRelays } = useFavoriteRelays()
const { relayList } = useNostr()
const relayInputsKey = useMemo(
() => stableRelayInputsKey(favoriteRelays, blockedRelays, relayList),
[favoriteRelays, blockedRelays, relayList]
)
const relayUrls = useMemo(() => {
const stacked = appendCuratedReadOnlyRelays(
getRelayUrlsWithFavoritesFastReadAndInbox(
@ -106,10 +131,14 @@ export default function ExploreRelayReviews() { @@ -106,10 +131,14 @@ export default function ExploreRelayReviews() {
),
blockedRelays
)
return stacked.slice(0, EXPLORE_REVIEWS_MAX_RELAYS)
}, [favoriteRelays, blockedRelays, relayList])
const sliced = stacked.slice(0, EXPLORE_REVIEWS_MAX_RELAYS)
const normalized = sliced.map((u) => normalizeAnyRelayUrl(u) || u.trim()).filter(Boolean)
normalized.sort((a, b) => a.localeCompare(b))
return normalized
// eslint-disable-next-line react-hooks/exhaustive-deps -- relayInputsKey is a content hash of favorites/blocked/NIP-65; relayList identity churn must not re-open REQ sockets.
}, [relayInputsKey])
const relayUrlsKey = useMemo(() => relayUrls.join('|'), [relayUrls])
const relayUrlsKey = relayInputsKey
const [loading, setLoading] = useState(true)
const [events, setEvents] = useState<Event[]>([])

7
src/components/RelayIcon/index.tsx

@ -32,13 +32,16 @@ function resolveRelayImageUrl(raw: string, relayUrl: string): string | undefined @@ -32,13 +32,16 @@ function resolveRelayImageUrl(raw: string, relayUrl: string): string | undefined
export default function RelayIcon({
url,
className,
iconSize = 14
iconSize = 14,
/** When true, do not hit NIP-11 (parent already fetches relay info, or icon-only row). */
skipRelayInfoFetch = false
}: {
url?: string
className?: string
iconSize?: number
skipRelayInfoFetch?: boolean
}) {
const { relayInfo } = useFetchRelayInfo(url)
const { relayInfo } = useFetchRelayInfo(skipRelayInfoFetch ? undefined : url)
const iconUrl = useMemo(() => {
if (!url) return undefined

2
src/components/RelayInfo/RelayReviewCard.tsx

@ -28,7 +28,7 @@ export default function RelayReviewCard({ @@ -28,7 +28,7 @@ export default function RelayReviewCard({
const { navigateToRelay } = useSmartRelayNavigation()
const stars = useMemo(() => getStarsFromRelayReviewEvent(event), [event])
const relayUrl = useMemo(() => getRelayUrlFromRelayReviewEvent(event), [event])
const { relayInfo } = useFetchRelayInfo(relayUrl)
const { relayInfo } = useFetchRelayInfo(showRelayInfo ? relayUrl : undefined)
return (
<div

6
src/hooks/useFetchRelayInfo.tsx

@ -8,7 +8,11 @@ export function useFetchRelayInfo(url?: string) { @@ -8,7 +8,11 @@ export function useFetchRelayInfo(url?: string) {
const [relayInfo, setRelayInfo] = useState<TRelayInfo | undefined>(undefined)
useEffect(() => {
if (!url) return
if (!url) {
setRelayInfo(undefined)
setIsFetching(false)
return
}
const fetchRelayInfos = async () => {
setIsFetching(true)
const timer = setTimeout(() => {

Loading…
Cancel
Save