| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| import {useCallback, useState} from 'react';
|
|
|
| type ThrottleOptions = {
|
| enableThrottling?: boolean;
|
| };
|
| type State = {
|
| isThrottled: boolean;
|
| maxThrottles: boolean;
|
| throttle: (callback: () => void, options?: ThrottleOptions) => void;
|
| };
|
|
|
| export default function useFunctionThrottle(
|
| initialDelay: number,
|
| numThrottles: number,
|
| ): State {
|
| const [isThrottled, setIsThrottled] = useState<boolean>(false);
|
| const [lastClickTime, setLastClickTime] = useState<number | null>(null);
|
| const [numTimesThrottled, setNumTimesThrottled] = useState<number>(1);
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| const throttle = useCallback(
|
| (
|
| callback: () => void,
|
| options: ThrottleOptions = {
|
| enableThrottling: true,
|
| },
|
| ) => {
|
| if (isThrottled) {
|
| return;
|
| }
|
|
|
| const currentTime = Date.now();
|
| if (lastClickTime == null) {
|
| callback();
|
| setLastClickTime(currentTime);
|
| return;
|
| }
|
|
|
| const timeBetweenClicks = currentTime - lastClickTime;
|
| const delay = initialDelay * numTimesThrottled;
|
| const shouldThrottle =
|
| options.enableThrottling && delay > timeBetweenClicks;
|
|
|
| if (shouldThrottle) {
|
| setIsThrottled(true);
|
| setTimeout(() => {
|
| setIsThrottled(false);
|
| }, delay);
|
| setNumTimesThrottled(prev => {
|
| return prev === numThrottles ? numThrottles : prev + 1;
|
| });
|
| }
|
|
|
| callback();
|
| setLastClickTime(currentTime);
|
| },
|
| [initialDelay, numThrottles, isThrottled, lastClickTime, numTimesThrottled],
|
| );
|
|
|
| return {
|
| isThrottled,
|
| maxThrottles: numTimesThrottled === numThrottles,
|
| throttle,
|
| };
|
| }
|
|
|