( func: T, wait?: number, options?: Options, forceUpdate?: Dispatch<SetStateAction<object>> )
| 119 | * const status = debounced.isPending() ? "Pending..." : "Ready" |
| 120 | */ |
| 121 | export 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; |
searching dependent graphs…