Skip to content

Commit

Permalink
Added isDebouncing flag to useDebouncedValue
Browse files Browse the repository at this point in the history
  • Loading branch information
bmingles committed Jan 26, 2024
1 parent 45fa929 commit aaea04b
Showing 1 changed file with 24 additions and 5 deletions.
29 changes: 24 additions & 5 deletions packages/react-hooks/src/useDebouncedValue.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,44 @@
import { useEffect, useState } from 'react';
import { useEffect, useMemo, useState } from 'react';

/**
* Debounces a value.
* Returns the initial value immediately.
* Returns the latest value after no changes have occurred for the debounce duration.
* @param value Value to debounce
* @param debounceMs Amount of time to debounce
* @returns The debounced value
* @returns The debounced value + whether the value is still debouncing
*/
export function useDebouncedValue<T>(value: T, debounceMs: number): T {
export function useDebouncedValue<T>(
value: T,
debounceMs: number
): { isDebouncing: boolean; value: T } {
const [isDebouncing, setIsDebouncing] = useState(true);
const [debouncedValue, setDebouncedValue] = useState<T>(value);

// Set isDebouncing to true immediately whenever the value changes. Using
// `useMemo` instead of `useEffect` so that state is never out of sync whenever
// value and / or debounceMs have changed.
useMemo(() => {
setIsDebouncing(true);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [value, debounceMs]);

useEffect(() => {
let isCancelled = false;

const timeoutId = setTimeout(() => {
setDebouncedValue(value);
if (!isCancelled) {
setIsDebouncing(false);
setDebouncedValue(value);
}
}, debounceMs);
return () => {
isCancelled = true;
clearTimeout(timeoutId);
};
}, [value, debounceMs]);

return debouncedValue;
return { isDebouncing, value: debouncedValue };
}

export default useDebouncedValue;

0 comments on commit aaea04b

Please sign in to comment.