Skip to content

fix: search results flickering and mixing in explorer#465

Open
pablocampogo wants to merge 2 commits into
mainfrom
fix-search-bar
Open

fix: search results flickering and mixing in explorer#465
pablocampogo wants to merge 2 commits into
mainfrom
fix-search-bar

Conversation

@pablocampogo

Copy link
Copy Markdown
Contributor

Fix search results flickering and cross-search value mixing

Summary

The Search view had two visible bugs:

  1. Flicker to loading while idle — leaving a search open caused the results panel to swap to the "Searching…" spinner every time background data (e.g. the validators poll) refreshed, instead of keeping the current values on screen.
  2. Stale / mixed results across searches — searching one address then another could keep the previous address's values on screen, and the whole results box would visibly disappear and reappear instead of updating in place.

Root causes

  • useSearch re-ran its full search on every dependency change (including background React Query refetches) and immediately did setResults(null) + setLoading(true), blanking the panel.
  • Results were published in a single setResults only after await Promise.all(...), which always includes a full AllOrders() order-book scan — so a fast address lookup was held hostage by the slowest source, leaving the old result on screen.
  • There was no request sequencing, so a slower earlier search could overwrite a newer one.
  • AddressResult was declared inside SearchResults, giving it a new component identity every render → React remounted (and re-fetched) it on every update, and content-based keys made cards blink on every change.

Changes

hooks/useSearch.ts

  • Added a per-invocation requestId guard so stale (superseded) searches can't overwrite newer results or clear the newer search's state.
  • Keep previous results mounted while a new query runs (no setResults(null)); values are swapped in place when ready.
  • Publish results progressively as each source resolves (guarded), so fast lookups render immediately instead of waiting for the slow order scan. Uses Promise.allSettled + a final forced publish that also renders the "no results" state.
  • loading now means "first search only" (isSearching && !results); later searches update in place. Also exposes isSearching.
  • Trims the search term and resets cleanly on empty input.

components/search/SearchResults.tsx

  • Moved AddressResult (and copyToClipboard) to module scope for a stable component identity, so cards update in place rather than remounting.
  • Added a fetch-cancellation guard in AddressResult so a stale response can't overwrite a newer address.
  • Keyed result cards by slot position so switching searches updates the existing card (no disappear/reappear blink).
  • Reset pagination to page 1 when the search term changes (panel now persists across searches).

pages/Search.tsx

  • Minor spacing tweak: added mt-4 to the Related Searches container.

Result

  • Idle/background refresh updates values in place — no flicker to the spinner.
  • Switching addresses replaces results as soon as the new lookup returns; the previous address never lingers.
  • The results box stays mounted and updates its values instead of blinking.
  • Spinner appears only on the very first search.

@pablocampogo pablocampogo requested a review from rem1niscence July 9, 2026 05:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant