Skip to content

fix: optimize GitHub search with debounce and request cancellation#355

Open
Tanayajadhav1 wants to merge 3 commits into
GitMetricsLab:mainfrom
Tanayajadhav1:feat/optimize-api-requests-debounce
Open

fix: optimize GitHub search with debounce and request cancellation#355
Tanayajadhav1 wants to merge 3 commits into
GitMetricsLab:mainfrom
Tanayajadhav1:feat/optimize-api-requests-debounce

Conversation

@Tanayajadhav1
Copy link
Copy Markdown

@Tanayajadhav1 Tanayajadhav1 commented May 21, 2026

Related Issue

Description

This PR optimizes GitHub search request handling to reduce excessive API calls and improve UI responsiveness during rapid input changes.

Changes Made

  • Added a reusable useDebounce hook for controlled input handling
  • Implemented debounced GitHub username search requests
  • Added request cancellation using AbortController
  • Prevented stale/outdated API responses from updating the UI
  • Added cleanup for pending requests on component unmount
  • Optimized filtering behavior using debounced filter inputs
  • Improved overall search responsiveness and reduced unnecessary GitHub API usage

Benefits

  • Reduces excessive GitHub API requests
  • Prevents overlapping in-flight requests
  • Minimizes risk of hitting GitHub API rate limits
  • Prevents stale data and UI flickering
  • Improves user experience during fast typing/searching

How Has This Been Tested?

  • Manually tested username search behavior
  • Verified that API requests are delayed while typing
  • Confirmed previous requests are cancelled during rapid input changes
  • Checked that the latest response updates the UI correctly

Type of Change

  • Bug fix
  • New feature
  • Code style update
  • Breaking change
  • Documentation update

Recommended Labels :

gssoc26, level:critical, enhancement, frontend, type:fix

Summary by CodeRabbit

  • New Features

    • Added debounced user inputs for improved performance and responsiveness
    • Automatic data fetching when search parameters change; removed form submission requirement
  • Bug Fixes

    • Enhanced error handling for GitHub API interactions with better messaging
    • Implemented request cancellation to prevent stale data updates

Review Change Stack

Copilot AI review requested due to automatic review settings May 21, 2026 04:56
@netlify
Copy link
Copy Markdown

netlify Bot commented May 21, 2026

Deploy Preview for github-spy failed.

Name Link
🔨 Latest commit 1faa61d
🔍 Latest deploy log https://app.netlify.com/projects/github-spy/deploys/6a0e96dc461c320008abae2f

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 21, 2026

Warning

Rate limit exceeded

@Tanayajadhav1 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 32 minutes and 44 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 82fa047a-b6c4-4f2d-b0d1-4bae13f7cb90

📥 Commits

Reviewing files that changed from the base of the PR and between 86418ac and 1faa61d.

📒 Files selected for processing (3)
  • src/hooks/useDebounce.ts
  • src/hooks/useGitHubData.ts
  • src/pages/Tracker/Tracker.tsx
📝 Walkthrough

Walkthrough

This PR introduces debounced input handling and request cancellation to prevent excessive GitHub API calls during rapid user input. A new useDebounce hook is added, useGitHubData is enhanced with AbortController support for canceling in-flight requests, and the Tracker component integrates debounced values for auto-fetching and filtering while removing form-based submission.

Changes

Debounced Input and Request Cancellation

Layer / File(s) Summary
useDebounce hook
src/hooks/useDebounce.ts
New generic hook that returns a debounced version of an input value with configurable delay (default 300ms) using internal state and timeout scheduling.
useGitHubData request cancellation infrastructure
src/hooks/useGitHubData.ts
Adds AbortController ref, cancelPendingRequest callback, and unmount cleanup effect to manage in-flight request cancellation.
useGitHubData fetch improvements
src/hooks/useGitHubData.ts
Extends fetchPaginated to accept AbortSignal, reworks fetchData with username validation, Octokit initialization checks, prior request cancellation, abort signal wiring, guarded state updates, and expanded error handling including rate limiting detection.
Tracker debounced inputs and auto-fetch
src/pages/Tracker/Tracker.tsx
Imports useDebounce and introduces debounced state for username, search title, repository, and date range. Implements effect that auto-triggers fetchData when debounced username changes, resetting pagination to page 0.
Tracker filtering with debounced values
src/pages/Tracker/Tracker.tsx
Updates filterData function to apply search title, repository, and date range filters using debounced values instead of immediate input states.
Tracker auth UI refactor
src/pages/Tracker/Tracker.tsx
Replaces form-based authentication with direct text input fields for username and token, removing required field validation and the "Fetch Data" submit button.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related issues

Possibly related PRs

  • GitMetricsLab/github_tracker#255: Both PRs modify the same fetch flow in useGitHubData and Tracker component—this PR adds debounced inputs and request cancellation, while the other refactors to server-side filtering, creating potential conflict.
  • GitMetricsLab/github_tracker#149: Both PRs modify useGitHubData fetch patterns—this PR adds abort/cancellation support while the other implements paginated Promise.all concurrent fetching and total counts.

Suggested labels

level:advanced, quality:clean

Poem

🐰 A hop through debounced delays,
Where rapid keystrokes find their ways,
Requests abort before they fly—
No API storms beneath the sky!
Clean input flows, the tracker sings. ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly summarizes the main changes: optimizing GitHub search with debounce and request cancellation, which aligns with the primary objectives.
Description check ✅ Passed The PR description includes all required template sections with detailed information about changes, testing, and type of change selection.
Linked Issues check ✅ Passed The PR successfully implements all core objectives from #341: debouncing input, cancelling in-flight requests via AbortController, preventing stale responses, and optimizing search behavior.
Out of Scope Changes check ✅ Passed All changes are directly scoped to requirements in #341: new useDebounce hook, abort request handling, debounced search, and optimized filtering align with stated objectives.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ 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.

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR improves the Tracker page’s GitHub username search UX by debouncing user input and cancelling in-flight GitHub Search API requests to reduce redundant calls and avoid stale responses updating the UI.

Changes:

  • Added a reusable useDebounce hook and applied debouncing to username input and filter fields.
  • Updated useGitHubData to support request cancellation via AbortController and to ignore aborted requests.
  • Refactored Tracker.tsx to auto-fetch data based on debounced username input and to use debounced values for client-side filtering.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
src/pages/Tracker/Tracker.tsx Debounces username + filters, switches to auto-fetch behavior, updates auth input UI.
src/hooks/useGitHubData.ts Adds abort-based request cancellation and input validation to reduce stale/overlapping requests.
src/hooks/useDebounce.ts Introduces a generic debounce hook used by the Tracker page.
Comments suppressed due to low confidence (2)

src/pages/Tracker/Tracker.tsx:102

  • Pagination is broken: the effect always fetches page 1 and never refetches when page changes, so TablePagination updates the page state without loading new results. Update the fetch trigger to include page (and pass page + 1), and only reset to page 0 when the username changes (not on every effect run).

This issue also appears on line 92 of the same file.

  // Auto-fetch data when debounced username, tab, or page changes
  useEffect(() => {
    if (debouncedUsername) {
      setPage(0);
      fetchData(debouncedUsername, 1, ROWS_PER_PAGE);
    }
  }, [tab, debouncedUsername, fetchData]);

  const handlePageChange = (_: unknown, newPage: number) => {
    setPage(newPage);
  };

src/pages/Tracker/Tracker.tsx:98

  • tab is included in the fetch effect dependencies, but fetchData already fetches both issues and PRs; switching tabs will unnecessarily re-hit the GitHub Search API and can increase rate-limit pressure. Consider removing tab from the dependencies (or change fetchData to fetch only the active tab’s data).
  // Auto-fetch data when debounced username, tab, or page changes
  useEffect(() => {
    if (debouncedUsername) {
      setPage(0);
      fetchData(debouncedUsername, 1, ROWS_PER_PAGE);
    }
  }, [tab, debouncedUsername, fetchData]);

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/pages/Tracker/Tracker.tsx
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

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

⚠️ Outside diff range comments (1)
src/hooks/useGitHubData.ts (1)

75-120: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Scope error and loading updates to the active controller.

The success path is guarded, but catch and finally are not. A canceled or superseded request can still set a stale error or flip loading to false while the newer request is still running.

💡 Suggested fix
-      abortControllerRef.current = new AbortController();
-      const signal = abortControllerRef.current.signal;
+      const controller = new AbortController();
+      abortControllerRef.current = controller;
+      const { signal } = controller;

       setLoading(true);
       setError('');

       try {
         const [issueRes, prRes] = await Promise.all([
           fetchPaginated(octokit, username, 'issue', page, perPage, signal),
           fetchPaginated(octokit, username, 'pr', page, perPage, signal),
         ]);

-        if (!signal.aborted) {
+        if (abortControllerRef.current === controller && !signal.aborted) {
           setIssues(issueRes.items);
           setPrs(prRes.items);
           setTotalIssues(issueRes.total);
           setTotalPrs(prRes.total);
           setRateLimited(false);
         }
       } catch (err: any) {
         if (err.name === 'AbortError') {
           return;
         }
+
+        if (abortControllerRef.current !== controller || signal.aborted) {
+          return;
+        }

         const errorMessage = err.message?.toLowerCase() || "";
         if (err.status === 403) {
           setError('GitHub API rate limit exceeded. Please provide a PAT to continue.');
           setRateLimited(true);
         } else if (errorMessage.includes("do not exist")) {
           setError('User not found. Please check the spelling of the GitHub username.');
         } else if (err.status === 401 || errorMessage.includes("permission")) {
           setError('Private repository detected. Please input PAT.');
         } else if (err.status === 404) {
           setError('Resource not found.');
         } else if (errorMessage.includes("validation failed")) {
           setError('Invalid GitHub username or insufficient permissions.');
         } else {
           setError(
             'Unable to fetch GitHub data. Please verify the username, token, or network connection.'
           );
         }
       } finally {
-        setLoading(false);
+        if (abortControllerRef.current === controller) {
+          abortControllerRef.current = null;
+          setLoading(false);
+        }
       }
🤖 Prompt for 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.

In `@src/hooks/useGitHubData.ts` around lines 75 - 120, Capture the active
AbortController at the start of the fetch (e.g., const currentController =
abortControllerRef.current) and, in the catch and finally blocks, guard all
state updates (setError, setRateLimited, setLoading, etc.) by checking that the
controller still equals currentController and that
!currentController.signal.aborted; also return early for AbortError as already
done so cancelled or superseded requests cannot overwrite state for a newer
request (apply these checks where you currently unguardedly call setError and
setLoading).
🤖 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/useGitHubData.ts`:
- Around line 58-72: Move the call to cancelPendingRequest() to the top of
fetchData (before any early-return validation), so any existing in-flight
request is aborted before you check username or octokit; specifically, call
cancelPendingRequest() before validating username (the setError('Please enter a
GitHub username.') path) and before checking getOctokit() (the
setError('Authentication not initialized.') path) to prevent stale responses
from repopulating results when those early returns occur.

In `@src/pages/Tracker/Tracker.tsx`:
- Around line 92-98: The effect currently hardcodes page 1 and omits the page
state from the dependency list so pagination UI changes don't trigger new
fetches; update the effect to use the page state (call
fetchData(debouncedUsername, page + 1, ROWS_PER_PAGE)), include page in the
dependency array ([tab, debouncedUsername, page, fetchData]) and keep setPage(0)
when debouncedUsername changes so a username reset triggers a page reset and the
subsequent effect run will fetch the correct first page; reference useEffect,
debouncedUsername, setPage, page, fetchData, and ROWS_PER_PAGE to locate
changes.
- Around line 139-141: The end-date filter in Tracker.tsx currently compares
item.created_at to the start of debouncedEndDate which excludes items later that
same day; update the comparison to treat the end date as inclusive by converting
debouncedEndDate to the end of that day (e.g., set hours to 23:59:59.999) or by
comparing item.created_at < startOfNextDay(debouncedEndDate) so items created
anytime on debouncedEndDate are kept; apply this change where filtered is
assigned and you use debouncedEndDate and item.created_at.

---

Outside diff comments:
In `@src/hooks/useGitHubData.ts`:
- Around line 75-120: Capture the active AbortController at the start of the
fetch (e.g., const currentController = abortControllerRef.current) and, in the
catch and finally blocks, guard all state updates (setError, setRateLimited,
setLoading, etc.) by checking that the controller still equals currentController
and that !currentController.signal.aborted; also return early for AbortError as
already done so cancelled or superseded requests cannot overwrite state for a
newer request (apply these checks where you currently unguardedly call setError
and setLoading).
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 61bf345f-19f1-40dd-ba2d-6df53d2eb406

📥 Commits

Reviewing files that changed from the base of the PR and between 9d34c19 and 86418ac.

📒 Files selected for processing (3)
  • src/hooks/useDebounce.ts
  • src/hooks/useGitHubData.ts
  • src/pages/Tracker/Tracker.tsx

Comment thread src/hooks/useGitHubData.ts Outdated
Comment thread src/pages/Tracker/Tracker.tsx Outdated
Comment thread src/pages/Tracker/Tracker.tsx Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

Comment thread src/hooks/useGitHubData.ts
Comment thread src/hooks/useGitHubData.ts
Comment thread src/hooks/useGitHubData.ts
Comment thread src/pages/Tracker/Tracker.tsx
Comment thread src/pages/Tracker/Tracker.tsx Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Enhancement] Improve Search Request Handling to Prevent Excessive GitHub API Calls During Rapid Input

2 participants