fix: optimize GitHub search with debounce and request cancellation#355
fix: optimize GitHub search with debounce and request cancellation#355Tanayajadhav1 wants to merge 3 commits into
Conversation
❌ Deploy Preview for github-spy failed.
|
|
Warning Rate limit exceeded
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 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 configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughThis PR introduces debounced input handling and request cancellation to prevent excessive GitHub API calls during rapid user input. A new ChangesDebounced Input and Request Cancellation
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Possibly related issues
Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
🎉 Thank you @Tanayajadhav1 for your contribution. Please make sure your PR follows https://github.com/GitMetricsLab/github_tracker/blob/main/CONTRIBUTING.md#-pull-request-guidelines
There was a problem hiding this comment.
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
useDebouncehook and applied debouncing to username input and filter fields. - Updated
useGitHubDatato support request cancellation viaAbortControllerand to ignore aborted requests. - Refactored
Tracker.tsxto 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
pagechanges, soTablePaginationupdates the page state without loading new results. Update the fetch trigger to includepage(and passpage + 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
tabis included in the fetch effect dependencies, butfetchDataalready fetches both issues and PRs; switching tabs will unnecessarily re-hit the GitHub Search API and can increase rate-limit pressure. Consider removingtabfrom the dependencies (or changefetchDatato 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.
There was a problem hiding this comment.
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 winScope
errorandloadingupdates to the active controller.The success path is guarded, but
catchandfinallyare not. A canceled or superseded request can still set a stale error or fliploadingtofalsewhile 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
📒 Files selected for processing (3)
src/hooks/useDebounce.tssrc/hooks/useGitHubData.tssrc/pages/Tracker/Tracker.tsx
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
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
useDebouncehook for controlled input handlingAbortControllerBenefits
How Has This Been Tested?
Type of Change
Recommended Labels :
gssoc26, level:critical, enhancement, frontend, type:fix
Summary by CodeRabbit
New Features
Bug Fixes