Debounce onChange callback that only fires on user input

25 views Asked by At

I want to debounce the value coming from <SomeComp onChange. The onChange callback is defined as (value: string) => void

So I did this:

function MyComponent(onDebounceChange) {
  const [value, setValue] = useState('');
  const debouncedValue = useDebounce(value, 500);

  useEffect(() => {
    onDebounceChange?.(debouncedValue);
  }, [debouncedValue]);

  return <SomeComp onChange={setValue} />
}

function useDebounce<T>(value: T, delay: number = 500): T {
    const [debouncedValue, setDebouncedValue] = useState<T>(value);

    useEffect(() => {
        const timeoutId = setTimeout(() => setDebouncedValue(value), delay);

        return () => {
            clearTimeout(timeoutId);
        };
    }, [value, delay]);

    return debouncedValue;
}

However the onDebounceChange callback is called on render and HMR. Vite is doing the HMR.

I can fix the render callback by using an initial state.

const [initial, setInitial] = useState(true);
useEffect(() => {
  setInitial(false);
}, []);

useEffect(() => {
  if (initial) return;
  onDebounceChange?.(debouncedValue);
}, [debouncedValue]);

But that doesn't fix callbacks triggered by HMR.

How do I prevent these programmatical callbacks. I only ever want these callbacks when a user interacted with the UI.

I do not have access to the "raw" <input onChange>. All I have is <SomeComp onChange={} />

0

There are 0 answers