Skip to content

Commit c757b5e

Browse files
committed
fix: do not overwrite local search component state while we are still debouncing
1 parent 2095f06 commit c757b5e

File tree

1 file changed

+24
-15
lines changed

1 file changed

+24
-15
lines changed

src/components/FilterComponents.tsx

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as React from 'react'
2-
import { useState, useRef, useEffect } from 'react'
2+
import { useState, useRef, useEffect, useCallback } from 'react'
33
import {
44
Table,
55
List,
@@ -9,7 +9,7 @@ import {
99
RotateCcw,
1010
SlidersHorizontal,
1111
} from 'lucide-react'
12-
import { useDebouncedValue } from '@tanstack/react-pacer'
12+
import { useDebouncedCallback, useDebouncer } from '@tanstack/react-pacer'
1313
import { twMerge } from 'tailwind-merge'
1414
import type { FeedViewMode } from '~/db/types'
1515

@@ -562,28 +562,37 @@ export function FilterSearch({
562562
// Local state for immediate UI updates
563563
const [inputValue, setInputValue] = useState(value || '')
564564

565-
// Debounce the input value
566-
const [debouncedValue] = useDebouncedValue(inputValue, {
567-
wait: debounceMs,
568-
})
569-
570-
// Update parent when debounced value changes
571-
React.useEffect(() => {
572-
onChange(debouncedValue)
573-
// eslint-disable-next-line react-hooks/exhaustive-deps
574-
}, [debouncedValue])
565+
const { maybeExecute, state: isPending } = useDebouncer(
566+
onChange,
567+
{ wait: debounceMs },
568+
(state) => ({
569+
isPending: state.isPending,
570+
}),
571+
)
575572

576573
// Sync local state when value prop changes externally
577574
React.useEffect(() => {
578-
setInputValue(value || '')
579-
}, [value])
575+
const nextValue = value || ''
576+
577+
setInputValue((currentValue) => {
578+
// While the user is editing, keep the local draft authoritative.
579+
if (isPending) {
580+
return currentValue
581+
}
582+
583+
return nextValue
584+
})
585+
}, [isPending, value])
580586

581587
return (
582588
<input
583589
type="text"
584590
placeholder={placeholder}
585591
value={inputValue}
586-
onChange={(e) => setInputValue(e.target.value)}
592+
onChange={(e) => {
593+
setInputValue(e.target.value)
594+
maybeExecute(e.target.value)
595+
}}
587596
className={twMerge(
588597
'border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-black/40 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500',
589598
size === 'sm' ? 'px-2 py-1 text-xs' : 'px-2 py-1 text-sm',

0 commit comments

Comments
 (0)