Skip to content

Frontend: DashboardPage lookup has no AbortController — in-flight fetch not cancelled on rapid re-lookups #203

Description

@k-deejah

Difficulty: Advanced

Problem

1. DashboardPage.lookup() starts a fetch but never cancels it if the user changes the public key and searches again
frontend/src/pages/DashboardPage.tsx lines 22–38: the lookup function is an inline async that sets loading = true, fires fetch(), and updates state on response. If the user types a new key and clicks Lookup again while the first fetch is still in-flight, two fetches run concurrently. Whichever resolves last wins — the results can be from the first (stale) request.

2. Unlike useQueues which uses a cancelled flag, DashboardPage has no cleanup
frontend/src/hooks/useQueues.ts correctly uses let cancelled = false and checks it before calling setQueues(). The dashboard's inline lookup function has no equivalent guard — it will call setRecords(data) even after the component unmounts or after a second lookup has been initiated.

3. lookup is recreated on every render but never wrapped in useCallback
The function is defined inside the component body without useCallback, creating a new function reference on every render. While this has minimal direct performance impact, it prevents correct memoization if lookup is ever passed to a child component.

Impact: Race conditions between concurrent lookup requests produce flickering, stale results. If the component unmounts while a lookup is in-flight (e.g., user navigates away), React logs a "Can't perform state update on unmounted component" warning and may cause memory leaks.

Proposed Solution

  • Add an AbortController to lookup(): create a new controller on each call, cancel the previous one, pass signal to fetch().
  • Track the current controller in a useRef so it persists across renders.
  • Wrap lookup in useCallback with [publicKey] dependency.
  • Add a component unmount cleanup to abort any in-flight request.

Acceptance Criteria

  • lookup() uses AbortController to cancel previous in-flight requests
  • Previous fetch is aborted when a new lookup is started
  • fetch receives { signal: controller.signal }
  • Aborted request does not update component state
  • Unmount cleanup aborts any in-flight request
  • lookup wrapped in useCallback([publicKey])
  • No TypeScript errors introduced

Contributor Note

If assigned, your PR must show a test (in the future frontend test suite) that demonstrates the race condition is resolved, and explain the difference between the cancelled flag pattern used in useQueues and the AbortController approach.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions