Skip to content

Commit 1bc30f8

Browse files
committed
fix: properly debounce user search to prevent per-keystroke requests
1 parent 50b3694 commit 1bc30f8

File tree

1 file changed

+22
-12
lines changed

1 file changed

+22
-12
lines changed

dashboard/src/components/users/filters.tsx

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import useDirDetection from '@/hooks/use-dir-detection'
99
import { cn } from '@/lib/utils'
1010
import { debounce } from 'es-toolkit'
1111
import { RefreshCw, SearchIcon, Filter, X, ArrowUpDown, User, Calendar, ChartPie, ChevronDown } from 'lucide-react'
12-
import { useState, useMemo } from 'react'
12+
import { useState, useRef, useEffect } from 'react'
1313
import { useTranslation } from 'react-i18next'
1414
import { useGetUsers, UserStatus } from '@/service/api'
1515
import { RefetchOptions } from '@tanstack/react-query'
@@ -71,29 +71,39 @@ export const Filters = ({ filters, onFilterChange, refetch, advanceSearchOnOpen,
7171
const [isRefreshing, setIsRefreshing] = useState(false)
7272
const userQuery = useGetUsers(filters)
7373
const handleRefetch = refetch || userQuery.refetch
74+
const onFilterChangeRef = useRef(onFilterChange)
7475

75-
// Ultra-fast debounced search function
76-
const debouncedFilterChange = useMemo(
77-
() =>
78-
debounce((value: string) => {
79-
onFilterChange({
80-
search: value,
81-
offset: 0, // Reset to first page when search is updated
82-
})
83-
}, 25), // Ultra-fast debounce
84-
[onFilterChange],
76+
// Keep the ref in sync with the prop
77+
onFilterChangeRef.current = onFilterChange
78+
79+
// Create debounced function using es-toolkit, stored in ref to avoid recreation
80+
const debouncedFilterChangeRef = useRef(
81+
debounce((value: string) => {
82+
onFilterChangeRef.current({
83+
search: value,
84+
offset: 0,
85+
})
86+
}, 300)
8587
)
8688

89+
// Cleanup on unmount
90+
useEffect(() => {
91+
return () => {
92+
debouncedFilterChangeRef.current.cancel()
93+
}
94+
}, [])
95+
8796
// Handle input change
8897
const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
8998
const value = e.target.value
9099
setSearch(value)
91-
debouncedFilterChange(value)
100+
debouncedFilterChangeRef.current(value)
92101
}
93102

94103
// Clear search field
95104
const clearSearch = () => {
96105
setSearch('')
106+
debouncedFilterChangeRef.current.cancel()
97107
onFilterChange({
98108
search: '',
99109
offset: 0,

0 commit comments

Comments
 (0)