data-flow: add debounce to LibraryPage search and fix race condition
- Completed Actions 2.4.1.1, 2.4.1.2, and 2.4.1.4 - Action 2.4.1.1: Verified custom useDebounce hook exists (no external package needed) - Action 2.4.1.2: Added useDebounce hook with 300ms delay to LibraryPage search - Action 2.4.1.4: Fixed race condition by using debouncedSearchTerm for page reset - Search now fires 300ms after typing stops, reducing API calls - Page reset now waits for debounce to complete, preventing race conditions
This commit is contained in:
parent
a37c52890f
commit
ff589b73c5
2 changed files with 23 additions and 18 deletions
|
|
@ -632,32 +632,32 @@ Critical path dependencies:
|
|||
### Sub-Epic 2.4: Request Debouncing 🟢
|
||||
|
||||
#### Task 2.4.1: Add Debounce to Search Inputs
|
||||
- [ ] **Action 2.4.1.1**: Install `use-debounce` or implement custom hook
|
||||
- [x] **Action 2.4.1.1**: Install `use-debounce` or implement custom hook
|
||||
- **Scope**: `apps/web/package.json` - Add dependency (if using library)
|
||||
- **Dependencies**: None
|
||||
- **Dependencies**: None ✅
|
||||
- **Risk**: LOW
|
||||
- **Validation**: Package installed
|
||||
- **Rollback**: Remove from package.json
|
||||
- **Validation**: ✅ Custom `useDebounce` hook already exists at `apps/web/src/hooks/useDebounce.ts` with tests. No external package needed.
|
||||
- **Rollback**: N/A (custom implementation)
|
||||
|
||||
- [ ] **Action 2.4.1.2**: Add debounce to LibraryPage search
|
||||
- [x] **Action 2.4.1.2**: Add debounce to LibraryPage search
|
||||
- **Scope**: `apps/web/src/features/library/pages/LibraryPage.tsx:322-327` - Debounce `setSearchTerm`
|
||||
- **Dependencies**: Action 2.4.1.1 complete
|
||||
- **Dependencies**: Action 2.4.1.1 complete ✅
|
||||
- **Risk**: LOW
|
||||
- **Validation**: Search fires 300ms after typing stops
|
||||
- **Rollback**: Remove debounce
|
||||
- **Validation**: ✅ Added `useDebounce` hook with 300ms delay. Search term is debounced before being used in queryParams and queryKey. Search fires 300ms after typing stops.
|
||||
- **Rollback**: Remove debounce hook usage
|
||||
|
||||
- [ ] **Action 2.4.1.3**: Add debounce to all search inputs
|
||||
- **Scope**: Audit all search inputs, add debounce
|
||||
- **Dependencies**: Action 2.4.1.2 complete
|
||||
- **Dependencies**: Action 2.4.1.2 complete ✅
|
||||
- **Risk**: LOW
|
||||
- **Validation**: All searches debounced
|
||||
- **Rollback**: Remove debounce from each
|
||||
|
||||
- [ ] **Action 2.4.1.4**: Fix race condition in LibraryPage search/page reset
|
||||
- [x] **Action 2.4.1.4**: Fix race condition in LibraryPage search/page reset
|
||||
- **Scope**: `apps/web/src/features/library/pages/LibraryPage.tsx:116-120` - Use debounced search term for page reset
|
||||
- **Dependencies**: Action 2.4.1.2 complete
|
||||
- **Dependencies**: Action 2.4.1.2 complete ✅
|
||||
- **Risk**: LOW
|
||||
- **Validation**: Page resets only after debounce completes
|
||||
- **Validation**: ✅ Updated useEffect to use `debouncedSearchTerm` instead of `searchTerm` for page reset. Page resets only after debounce completes, fixing race condition.
|
||||
- **Rollback**: Restore original useEffect
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { useState, useMemo, useEffect } from 'react';
|
||||
import { useDebounce } from '@/hooks/useDebounce';
|
||||
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import {
|
||||
usePlaylists,
|
||||
|
|
@ -70,6 +71,8 @@ export default function LibraryPagePremium() {
|
|||
const [viewMode, setViewMode] = useState<ViewMode>('grid');
|
||||
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
// Action 2.4.1.2: Debounce search term to reduce API calls
|
||||
const debouncedSearchTerm = useDebounce(searchTerm, 300);
|
||||
const [genreFilter, setGenreFilter] = useState<string>('');
|
||||
const [formatFilter, setFormatFilter] = useState<string>('');
|
||||
const [sortBy, setSortBy] = useState<SortField>('created_at');
|
||||
|
|
@ -91,9 +94,10 @@ export default function LibraryPagePremium() {
|
|||
if (formatFilter) {
|
||||
queryParams.format = formatFilter;
|
||||
}
|
||||
if (searchTerm.trim()) {
|
||||
queryParams.search = searchTerm.trim();
|
||||
}
|
||||
// Use debounced search term for API calls
|
||||
if (debouncedSearchTerm.trim()) {
|
||||
queryParams.search = debouncedSearchTerm.trim();
|
||||
}
|
||||
|
||||
const {
|
||||
data: tracksData,
|
||||
|
|
@ -101,7 +105,7 @@ export default function LibraryPagePremium() {
|
|||
isError: isTracksError,
|
||||
error: tracksError,
|
||||
} = useQuery({
|
||||
queryKey: ['tracks', 'library', queryParams, searchTerm],
|
||||
queryKey: ['tracks', 'library', queryParams, debouncedSearchTerm],
|
||||
queryFn: () => getTracks(page, limit, queryParams),
|
||||
});
|
||||
|
||||
|
|
@ -113,11 +117,12 @@ export default function LibraryPagePremium() {
|
|||
return tracksData.tracks;
|
||||
}, [tracksData?.tracks]);
|
||||
|
||||
// Action 2.4.1.4: Use debounced search term for page reset to fix race condition
|
||||
useEffect(() => {
|
||||
if (searchTerm.trim() && page !== 1) {
|
||||
if (debouncedSearchTerm.trim() && page !== 1) {
|
||||
setPage(1);
|
||||
}
|
||||
}, [searchTerm]);
|
||||
}, [debouncedSearchTerm, page]);
|
||||
|
||||
const genres = Array.from(
|
||||
new Set(
|
||||
|
|
|
|||
Loading…
Reference in a new issue