UNPKG

use-hook-kits

Version:

![npm](https://img.shields.io/npm/dt/use-hook-kits.svg) ![npm](https://img.shields.io/npm/v/use-hook-kits.svg) ![NpmLicense](https://img.shields.io/npm/l/use-hook-kits.svg)

91 lines (77 loc) 2.93 kB
import { useRef, useCallback, useEffect } from 'react'; //{ maxWait?: number; leading?: boolean; trailing?: boolean } = {} export default function useThrottleCallback( callback, delay, options= {} ) { const maxWait = options.maxWait; const maxWaitHandler = useRef(null); const maxWaitArgs = useRef([]); const leading = options?.leading === undefined ? true : options.leading; const trailing = options?.trailing === undefined ? false : options.trailing; const leadingCall = useRef(false); const functionTimeoutHandler = useRef(null); const isComponentUnmounted = useRef(false); const throttleFunction = useRef(callback); throttleFunction.current = callback; const cancelthrottledCallback = useCallback(() => { clearTimeout(functionTimeoutHandler.current); clearTimeout(maxWaitHandler.current); maxWaitHandler.current = null; maxWaitArgs.current = []; functionTimeoutHandler.current = null; leadingCall.current = false; }, []); useEffect(() => { // We have to set isComponentUnmounted to be truth, as fast-refresh runs all useEffects isComponentUnmounted.current = false; return () => { // we use flag, as we allow to call callPending outside the hook isComponentUnmounted.current = true; }; }, []); const throttledCallback = useCallback( (...args) => { maxWaitArgs.current = args; clearTimeout(functionTimeoutHandler.current); if (leadingCall.current) { leadingCall.current = false; } if (!functionTimeoutHandler.current && leading && !leadingCall.current) { throttleFunction.current(...args); leadingCall.current = true; } functionTimeoutHandler.current = setTimeout(() => { let shouldCallFunction = true; if (leading && leadingCall.current) { shouldCallFunction = false; } cancelthrottledCallback(); if (!isComponentUnmounted.current && trailing && shouldCallFunction) { throttleFunction.current(...args); } }, delay); if (maxWait && !maxWaitHandler.current && trailing) { maxWaitHandler.current = setTimeout(() => { const args = maxWaitArgs.current; cancelthrottledCallback(); if (!isComponentUnmounted.current) { throttleFunction.current.apply(null, args); } }, maxWait); } }, [maxWait, delay, cancelthrottledCallback, leading, trailing] ); const callPending = useCallback(() => { // Call pending callback only if we have anything in our queue if (!functionTimeoutHandler.current) { return; } throttleFunction.current.apply(null, maxWaitArgs.current); cancelthrottledCallback(); }, [cancelthrottledCallback]); // At the moment, we use 3 args array so that we save backward compatibility return [throttledCallback, cancelthrottledCallback, callPending]; }