UNPKG

@supunlakmal/hooks

Version:

A collection of reusable React hooks

56 lines 3.12 kB
import { useEffect, useRef } from 'react'; // Helper hook to get the latest value of a variable (useful for callbacks in intervals/timeouts) function useLatest(value) { const ref = useRef(value); // No dependency array, updates on every render useEffect(() => { ref.current = value; }); return ref; } /** * A custom hook similar to `setInterval`, but the interval only runs when a specific * condition (`when`) is true. It clears the interval automatically on unmount or * when the `delay` or `when` condition changes appropriately. * * @param {() => void} callback The function to execute at each interval. * @param {number | null | undefined} delay The interval duration in milliseconds. * The interval is paused if `delay` is `null` or `undefined`, or if `when` is `false`. * @param {object} [options] Optional configuration options. * @param {boolean} [options.when=true] A boolean condition. The interval runs only when this is true. * @param {boolean} [options.startImmediate=false] If true, the callback is executed immediately * when the interval starts or resumes (i.e., when `when` becomes true and `delay` is valid). */ export const useIntervalWhen = (callback, delay, options) => { // Default options const { when = true, startImmediate = false } = options || {}; // Use refs to manage state across renders without triggering re-renders unnecessarily const savedCallback = useLatest(callback); // Store the latest callback const firstRunDoneRef = useRef(false); // Track if the immediate call was executed for the current active cycle useEffect(() => { // Determine the effective delay based on the 'when' condition and the provided delay const effectiveDelay = when && delay !== null && typeof delay !== 'undefined' ? delay : null; // If the interval should not be active, reset the immediate run tracker if (effectiveDelay === null) { firstRunDoneRef.current = false; return; // Exit early, no interval to set or clear (cleanup from previous effect handles it) } // --- Interval is active from this point --- const tick = () => savedCallback.current(); // Handle immediate execution if requested and not already done for this cycle if (startImmediate && !firstRunDoneRef.current) { tick(); // Execute immediately firstRunDoneRef.current = true; // Mark as executed } // Set up the interval using the effective delay const intervalId = setInterval(tick, effectiveDelay); // Return the cleanup function to clear the interval return () => { clearInterval(intervalId); // Reset the immediate run tracker *only* when the interval is cleared due to deps change // This allows immediate run again if `when` becomes true again after being false firstRunDoneRef.current = false; }; }, [delay, when, startImmediate, savedCallback]); // Dependencies that trigger effect re-run }; //# sourceMappingURL=useIntervalWhen.js.map