MCPcopy
hub / github.com/xnimorz/use-debounce / useDebouncedCallback

Function useDebouncedCallback

src/useDebouncedCallback.ts:121–330  ·  view source on GitHub ↗
(
  func: T,
  wait?: number,
  options?: Options,
  forceUpdate?: Dispatch<SetStateAction<object>>
)

Source from the content-addressed store, hash-verified

119 * const status = debounced.isPending() ? "Pending..." : "Ready"
120 */
121export default function useDebouncedCallback<
122 T extends (...args: any) => ReturnType<T>,
123>(
124 func: T,
125 wait?: number,
126 options?: Options,
127 forceUpdate?: Dispatch<SetStateAction<object>>
128): DebouncedState<T> {
129 const lastCallTime = useRef(null);
130 const lastInvokeTime = useRef(0);
131 const firstInvokeTime = useRef(0);
132 const timerId = useRef(null);
133 const lastArgs = useRef<unknown[]>([]);
134 const lastThis = useRef<unknown>();
135 const result = useRef<ReturnType<T>>();
136 const funcRef = useRef(func);
137 const mounted = useRef(true);
138 // Always keep the latest version of debounce callback, with no wait time.
139 funcRef.current = func;
140
141 const isClientSide = typeof window !== 'undefined';
142 // Bypass `requestAnimationFrame` by explicitly setting `wait=0`.
143 const useRAF = !wait && wait !== 0 && isClientSide;
144
145 if (typeof func !== 'function') {
146 throw new TypeError('Expected a function');
147 }
148
149 wait = +wait || 0;
150 options = options || {};
151
152 const leading = !!options.leading;
153 const trailing = 'trailing' in options ? !!options.trailing : true; // `true` by default
154 const maxing = 'maxWait' in options;
155 const debounceOnServer =
156 'debounceOnServer' in options ? !!options.debounceOnServer : false; // `false` by default
157 const maxWait = maxing ? Math.max(+options.maxWait || 0, wait) : null;
158
159 useEffect(() => {
160 mounted.current = true;
161 return () => {
162 mounted.current = false;
163 };
164 }, []);
165
166 // You may have a question, why we have so many code under the useMemo definition.
167 //
168 // This was made as we want to escape from useCallback hell and
169 // not to initialize a number of functions each time useDebouncedCallback is called.
170 //
171 // It means that we have less garbage for our GC calls which improves performance.
172 // Also, it makes this library smaller.
173 //
174 // And the last reason, that the code without lots of useCallback with deps is easier to read.
175 // You have only one place for that.
176 const debounced = useMemo(() => {
177 const invokeFunc = (time: number) => {
178 const args = lastArgs.current;

Callers 3

ComponentFunction · 0.85
useThrottledCallbackFunction · 0.85
useDebounceFunction · 0.85

Calls 1

trailingEdgeFunction · 0.85

Tested by 1

ComponentFunction · 0.68

Used in the wild real call sites across dependent graphs

searching dependent graphs…