@ducor/hooks
Version:
A collection of useful React hooks for building modern web applications. Includes hooks for clipboard operations, window events, intervals, timeouts, and more.
62 lines (61 loc) • 2.11 kB
JavaScript
import { useCallback, useEffect, useRef } from "react";
/**
* A robust timeout hook with manual control and auto-invocation options
* @template T - Type of parameters passed to the callback
* @param callback - Function to execute after delay
* @param delay - Delay in milliseconds (null to disable)
* @param options - Configuration options
* @returns Object with control methods
*/
function useTimeout(callback, delay, options = { autoInvoke: false }) {
const timeoutRef = useRef(null);
const savedCallback = useRef(callback);
const savedDelay = useRef(delay);
// Always use the latest callback without resetting timeout
useEffect(() => {
savedCallback.current = callback;
}, [callback]);
// Update delay reference if it changes
useEffect(() => {
savedDelay.current = delay;
}, [delay]);
const clear = useCallback(() => {
if (timeoutRef.current) {
window.clearTimeout(timeoutRef.current);
timeoutRef.current = null;
}
}, []);
const start = useCallback((...args) => {
clear();
if (savedDelay.current !== null) {
timeoutRef.current = window.setTimeout(() => {
savedCallback.current(...args);
timeoutRef.current = null;
}, savedDelay.current);
}
}, [clear]);
const restart = useCallback((...args) => {
clear();
start(...args);
}, [clear, start]);
// Handle auto-invocation and cleanup
useEffect(() => {
if (options.autoInvoke && delay !== null) {
if (options.autoInvokeParams) {
start(...options.autoInvokeParams);
}
else {
// Safe cast since we know callback supports no params when autoInvokeParams isn't provided
start();
}
}
return clear;
}, [delay, options.autoInvoke, options.autoInvokeParams, start, clear]);
return {
start,
clear,
restart,
isActive: () => timeoutRef.current !== null,
};
}
export default useTimeout;