Skip to content

feat: add debounced search for pool filtering on Explore page#87

Open
Atharva0506 wants to merge 2 commits into
StabilityNexus:mainfrom
Atharva0506:feature/debounced-pool-search
Open

feat: add debounced search for pool filtering on Explore page#87
Atharva0506 wants to merge 2 commits into
StabilityNexus:mainfrom
Atharva0506:feature/debounced-pool-search

Conversation

@Atharva0506

@Atharva0506 Atharva0506 commented Mar 20, 2026

Copy link
Copy Markdown
Member

Addressed Issues:

Fixes #86

Screenshots/Recordings:

No visual screenshots applicable. The UI remains visually identical, but performance is optimized. The pool listing now has a 300ms rendering delay while actively typing in the search bar to prevent browser lag.

Additional Notes:

What was fixed and why:
The explorePools/page.tsx component was previously suffering from a performance bottleneck during search operations. The <PoolSearch /> component was passing the keystroke events directly to the searchQuery state, and the filteredPools useMemo block was depending directly on that raw state.
Because the useMemo block iterates over the entire pools array and applies 5 different lowercase string matching algorithms (includes) per pool, firing this evaluation synchronously on every single keystroke caused the main thread to block. On devices with lower processing power, or as the number of supported pools grows across multiple chains, this resulted in severe UI freezing and input lag.
Implementation Details:

  1. Created useDebouncedValue<T>: I added a generic, reusable React hook in src/hooks/useDebouncedValue.ts that safely delays state updates by a configured time (default 300ms) using setTimeout.
  2. Decoupled input state from filtering state: In explorePools/page.tsx, the searchQuery state is still updated instantly. This ensures the actual <input> element remains 100% responsive and never drops keystrokes.
  3. Optimized useMemo: The filteredPools array now depends on debouncedSearchQuery instead of searchQuery. This guarantees that the heavy array filtering operation only fires after the user pauses typing for 300ms, completely resolving the browser lag.

We encourage contributors to use AI tools responsibly when creating Pull Requests. While AI can be a valuable aid, it is essential to ensure that your contributions meet the task requirements, build successfully, include relevant tests, and pass all linters. Submissions that do not meet these standards may be closed without warning to maintain the quality and integrity of the project. Please take the time to understand the changes you are proposing and their impact. AI slop is strongly discouraged and may lead to banning and blocking. Do not spam our repos with AI slop.

Check one of the checkboxes below:

  • This PR does not contain AI-generated code at all.
  • This PR contains AI-generated code. I have read the AI Usage Policy and this PR complies with this policy. I have tested the code locally and I am responsible for it.

I have used the following AI models and tools: TODO

Checklist

  • My PR addresses a single issue, fixes a single bug or makes a single improvement.
  • My code follows the project's code style and conventions
  • If applicable, I have made corresponding changes or additions to the documentation
  • If applicable, I have made corresponding changes or additions to tests
  • My changes generate no new warnings or errors
  • I have joined the Discord server and I will share a link to this PR with the project maintainers there
  • I have read the Contribution Guidelines
  • Once I submit my PR, CodeRabbit AI will automatically review it and I will address CodeRabbit's comments.
  • I have filled this PR template completely and carefully, and I understand that my PR may be closed without review otherwise.

Summary by CodeRabbit

  • New Features
    • Improved Explore Pools search responsiveness by debouncing typed queries before updating results.
  • Bug Fixes
    • Reduced unnecessary re-filtering during rapid typing to keep displayed results in sync with the latest input.
  • Refactor
    • Moved reusable debounced value behavior into a dedicated hook for cleaner reuse across the app.

@coderabbitai

coderabbitai Bot commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

This PR introduces a reusable useDebouncedValue hook and integrates it into the explore pools page to delay search filtering by 300ms, reducing re-renders during active typing while maintaining responsive input field behavior.

Changes

Debounce Search Refactoring

Layer / File(s) Summary
New Debounced Value Hook
src/hooks/useDebouncedValue.ts
Added generic useDebouncedValue<T> hook that delays value updates using setTimeout with configurable delay (default 300ms). Includes proper cleanup to prevent stale timeouts.
Explore Pools Search Integration
src/app/explorePools/page.tsx
Integrated debounced hook into search workflow. Updated pool filtering to use debouncedSearchQuery instead of searchQuery, and adjusted useMemo dependency list accordingly for proper recomputation timing.
Optimized Data Hook Refactoring
src/hooks/useOptimizedData.ts
Removed generic useDebouncedSearch and consolidated caching, retry, abort, and lifecycle logic into useOptimizedData. Portfolio and pools wrapper hooks retain their thin abstraction layer and domain-specific configuration.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Suggested labels

Typescript Lang

Poem

🐰 A rabbit hops through queries fast,
No lag to make the search task vast,
Three hundred milliseconds' grace,
Keep the UI's gentle pace!

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding debounced search functionality for pool filtering on the Explore page, which is the primary purpose of this PR.
Linked Issues check ✅ Passed All objectives from issue #86 are fully met: a generic useDebouncedValue hook was created, debouncing is implemented in explorePools/page.tsx with 300ms delay, and input remains responsive while filtering is deferred.
Out of Scope Changes check ✅ Passed The removal of the unused useDebouncedSearch hook from useOptimizedData.ts is appropriate cleanup that was explicitly approved by the reviewer, and all changes directly support the debounced search implementation.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/app/explorePools/page.tsx (1)

563-576: 🧹 Nitpick | 🔵 Trivial

Compute searchLower once per memo, not once per pool.

At Line 566, debouncedSearchQuery.toLowerCase() is recalculated for every item in pools. Move it outside the filter callback to reduce repeated work on large lists.

♻️ Suggested refactor
-  const filteredPools = useMemo(
-    (): Pool[] =>
-      pools.filter((pool: Pool) => {
-        const searchLower = debouncedSearchQuery.toLowerCase();
+  const filteredPools = useMemo((): Pool[] => {
+      const searchLower = debouncedSearchQuery.toLowerCase();
+      return pools.filter((pool: Pool) => {
         const priceFeedName = getPriceFeedName(pool.priceFeedAddress, pool.chainId);
         return (
           pool.name.toLowerCase().includes(searchLower) ||
           pool.bullToken.symbol.toLowerCase().includes(searchLower) ||
           pool.bearToken.symbol.toLowerCase().includes(searchLower) ||
           pool.chainName.toLowerCase().includes(searchLower) ||
           priceFeedName.toLowerCase().includes(searchLower)
         );
-      }),
-    [pools, debouncedSearchQuery]
-  );
+      });
+    }, [pools, debouncedSearchQuery]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/explorePools/page.tsx` around lines 563 - 576, The filter currently
calls debouncedSearchQuery.toLowerCase() for every pool; compute searchLower
once outside the callback inside the useMemo to avoid repeated work: inside the
useMemo for filteredPools, create a const searchLower =
debouncedSearchQuery.toLowerCase() before pools.filter, then use that variable
within the filter callback along with existing helpers like
getPriceFeedName(pool.priceFeedAddress, pool.chainId); update the dependency
array stays [pools, debouncedSearchQuery].
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/hooks/useDebouncedValue.ts`:
- Line 1: This module uses React client hooks (useState, useEffect) in the
useDebouncedValue hook but lacks the Next.js client directive; add the exact
string "use client"; as the first line of the file (before any imports) so the
module is explicitly a client component/module and prevents server-boundary
misuse.

---

Outside diff comments:
In `@src/app/explorePools/page.tsx`:
- Around line 563-576: The filter currently calls
debouncedSearchQuery.toLowerCase() for every pool; compute searchLower once
outside the callback inside the useMemo to avoid repeated work: inside the
useMemo for filteredPools, create a const searchLower =
debouncedSearchQuery.toLowerCase() before pools.filter, then use that variable
within the filter callback along with existing helpers like
getPriceFeedName(pool.priceFeedAddress, pool.chainId); update the dependency
array stays [pools, debouncedSearchQuery].
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4b2ee4a5-d2db-463e-a51a-318415ff8057

📥 Commits

Reviewing files that changed from the base of the PR and between fbd27aa and 716123f.

📒 Files selected for processing (2)
  • src/app/explorePools/page.tsx
  • src/hooks/useDebouncedValue.ts

Comment thread src/hooks/useDebouncedValue.ts
@Atharva0506

Atharva0506 commented Mar 20, 2026

Copy link
Copy Markdown
Member Author

@blizet

there is already a useDebouncedSearch hook in src/hooks/useOptimizedData.ts, but I created a new useDebouncedValue hook for this PR instead.

Why?
The old hook only filters arrays by a single text field. We needed to filter 5 different fields at once (Pool name, Bull symbol, Bear symbol, Chain, and Oracle), so a generic value-based debounce was much better and let the input stay instantly responsive.

Question:
I also noticed the old useDebouncedSearch hook isn't being used anywhere in the codebase. Would you like me to delete that unused code in this PR to clean things up, or just leave it alone? Let me know!

@DengreSarthak

Copy link
Copy Markdown
Member

@Atharva0506 Yes, go ahead and remoVe it.

@Atharva0506

Copy link
Copy Markdown
Member Author

@DengreSarthak removed!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/hooks/useOptimizedData.ts`:
- Around line 85-92: The issue is that aborted requests still execute their
finally blocks and can set loading=false even while newer requests are pending,
causing the loading state to be incorrectly cleared. To fix this, add a request
ID or version tracking mechanism by creating a unique identifier when
instantiating the AbortController in the request initialization (around lines
85-92), store this identifier in a ref, and then in the finally block (lines
142-145) check that the stored request ID matches the current request ID before
setting loading=false. This ensures only the most recent request can clear the
loading state.
- Around line 149-165: When the key changes and no cached entry exists, the
previous data remains visible until the new fetch completes, causing stale data
from a different key to appear. In the useEffect hook, before calling
fetchData() without arguments (in the uncached fetch path after the cache
check), add a call to setData with an appropriate initial value (such as null or
an empty array depending on the data structure) to clear the previous key's data
immediately, ensuring users don't see stale cross-key data while the new fetch
is in progress.
- Around line 1-5: The useOptimizedData.ts hook module uses React client-side
hooks (useState, useEffect, useCallback, useMemo, useRef) but is missing the
required "use client" directive for Next.js. Add "use client" as the very first
line of the file, before all import statements, to explicitly mark this module
as a client component boundary.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0fcbeb25-46cb-456a-b5d1-e429f5b13b66

📥 Commits

Reviewing files that changed from the base of the PR and between 716123f and 35ff958.

📒 Files selected for processing (1)
  • src/hooks/useOptimizedData.ts

Comment thread src/hooks/useOptimizedData.ts
Comment thread src/hooks/useOptimizedData.ts
Comment thread src/hooks/useOptimizedData.ts
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.

[FEATURE]: Add Debounced Search to Explore Pools Page to Optimize Performance

2 participants