From f417ed8210433c53414bf37785adf16e840e8bd7 Mon Sep 17 00:00:00 2001 From: Gigi Date: Sun, 2 Nov 2025 23:08:20 +0100 Subject: [PATCH] fix: resolve race condition in profile label updates Fix regression where npubs/nprofiles weren't being replaced with profile names. The issue was a race condition: loading state was cleared immediately, but labels were applied asynchronously via RAF, causing the condition check to fail. Changes: - Apply profile labels immediately when profiles resolve, instead of batching via RAF - Update condition check to explicitly handle undefined loading state (isLoading !== true) - This ensures labels are available in the Map when loading becomes false --- src/hooks/useProfileLabels.ts | 14 +++++++++----- src/utils/nostrUriResolver.tsx | 7 +++++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/hooks/useProfileLabels.ts b/src/hooks/useProfileLabels.ts index 95428a0e..5bedb7d6 100644 --- a/src/hooks/useProfileLabels.ts +++ b/src/hooks/useProfileLabels.ts @@ -273,7 +273,7 @@ export function useProfileLabels( console.log(`[profile-loading-debug][profile-labels-loading] Starting fetch for ${pubkeysToFetch.length} profiles:`, pubkeysToFetch.map(p => p.slice(0, 16) + '...')) // Reactive callback: collects profile updates and batches them via RAF to prevent flicker - // Strategy: Collect updates in ref, schedule RAF on first update, apply all in batch + // Strategy: Apply label immediately when profile resolves, but still batch for multiple profiles const handleProfileEvent = (event: NostrEvent) => { // Use pubkey directly as the key const pubkey = event.pubkey @@ -282,10 +282,14 @@ export function useProfileLabels( const displayName = extractProfileDisplayName(event) const label = displayName ? (displayName.startsWith('@') ? displayName : `@${displayName}`) : getNpubFallbackDisplay(pubkey) - // Add to pending updates and schedule batched application - console.log(`[shimmer-debug][profile-labels] Adding to pending updates: ${pubkey.slice(0, 16)}...="${label}", pendingUpdates.size=${pendingUpdatesRef.current.size + 1}`) - pendingUpdatesRef.current.set(pubkey, label) - scheduleBatchedUpdate() + // Apply label immediately to prevent race condition with loading state + // This ensures labels are available when isLoading becomes false + console.log(`[shimmer-debug][profile-labels] Applying label immediately: ${pubkey.slice(0, 16)}...="${label}"`) + setProfileLabels(prevLabels => { + const updated = new Map(prevLabels) + updated.set(pubkey, label) + return updated + }) // Clear loading state for this profile when it resolves console.log(`[profile-loading-debug][profile-labels-loading] Profile resolved for ${pubkey.slice(0, 16)}..., CLEARING LOADING`) diff --git a/src/utils/nostrUriResolver.tsx b/src/utils/nostrUriResolver.tsx index 740371c6..83aa4ddb 100644 --- a/src/utils/nostrUriResolver.tsx +++ b/src/utils/nostrUriResolver.tsx @@ -339,12 +339,15 @@ export function replaceNostrUrisInMarkdownWithProfileLabels( const pubkey = decoded.type === 'npub' ? decoded.data : decoded.data.pubkey // Check if we have a resolved profile name using pubkey as key - // Only use Map value if profile is not loading (meaning it's actually resolved) + // Use the label if: 1) we have a label, AND 2) profile is not currently loading (false or undefined) const isLoading = profileLoading.get(pubkey) const hasLabel = profileLabels.has(pubkey) console.log(`[shimmer-debug][markdown-replace] ${decoded.type} pubkey=${pubkey.slice(0, 16)}..., isLoading=${isLoading}, hasLabel=${hasLabel}`) - if (!isLoading && hasLabel) { + // Use resolved label if we have one and profile is not loading + // isLoading can be: true (loading), false (loaded), or undefined (never was loading) + // We only avoid using the label if isLoading === true + if (isLoading !== true && hasLabel) { const displayName = profileLabels.get(pubkey)! console.log(`[shimmer-debug][markdown-replace] Using resolved name: ${displayName}`) return `[${displayName}](${link})`