useHooks.iov4.1.2
DocsBlogGitHub
Hooks
No hooks found in any category.

useTimeout

utilities

Installation

npx usehooks-cli@latest add use-timeout

Description

A React hook for managing timeouts with start, stop, reset, and status checking capabilities. Provides fine-grained control over timeout execution and automatically handles cleanup.

Parameters

NameTypeDefaultDescription
callback() => void-The function to execute when the timeout completes
delaynumber | null-The delay in milliseconds, or null to disable the timeout

Return Type

UseTimeoutReturn
PropertyTypeDescription
start() => voidStarts or restarts the timeout
stop() => voidStops the timeout and prevents the callback from executing
reset() => voidStops the current timeout and starts a new one
isActive() => booleanReturns true if the timeout is currently active

Examples

Auto-save Functionality

Implementing auto-save with manual control

1const [content, setContent] = useState(''); 2const [isSaved, setIsSaved] = useState(true); 3 4const saveContent = useCallback(() => { 5 // Save content to server 6 saveToServer(content); 7 setIsSaved(true); 8}, [content]); 9 10const { start, stop, reset, isActive } = useTimeout(saveContent, 2000); 11 12const handleContentChange = (newContent: string) => { 13 setContent(newContent); 14 setIsSaved(false); 15 reset(); // Reset the auto-save timer 16}; 17 18return ( 19 <div> 20 <textarea 21 value={content} 22 onChange={(e) => handleContentChange(e.target.value)} 23 /> 24 <div> 25 {isSaved ? 'Saved' : isActive() ? 'Auto-saving...' : 'Not saved'} 26 </div> 27 <button onClick={stop}>Cancel Auto-save</button> 28 </div> 29);

Notification Auto-dismiss

Auto-dismissing notifications with pause/resume

1const [notification, setNotification] = useState(null); 2 3const dismissNotification = useCallback(() => { 4 setNotification(null); 5}, []); 6 7const { start, stop, reset } = useTimeout(dismissNotification, 5000); 8 9const showNotification = (message: string) => { 10 setNotification(message); 11 reset(); // Start auto-dismiss timer 12}; 13 14return ( 15 <div> 16 {notification && ( 17 <div 18 className="notification" 19 onMouseEnter={stop} // Pause on hover 20 onMouseLeave={start} // Resume on leave 21 > 22 {notification} 23 <button onClick={dismissNotification}>×</button> 24 </div> 25 )} 26 </div> 27);

Delayed Action with Cancellation

Implementing delayed actions that can be cancelled

1const [isDeleting, setIsDeleting] = useState(false); 2 3const performDelete = useCallback(() => { 4 // Perform actual deletion 5 deleteItem(); 6 setIsDeleting(false); 7}, []); 8 9const { start, stop, isActive } = useTimeout(performDelete, 3000); 10 11const handleDeleteClick = () => { 12 setIsDeleting(true); 13 start(); 14}; 15 16const cancelDelete = () => { 17 stop(); 18 setIsDeleting(false); 19}; 20 21return ( 22 <div> 23 {isDeleting ? ( 24 <div> 25 <p>Deleting in {isActive() ? '3' : '0'} seconds...</p> 26 <button onClick={cancelDelete}>Cancel</button> 27 </div> 28 ) : ( 29 <button onClick={handleDeleteClick}>Delete Item</button> 30 )} 31 </div> 32);

Dependencies

react

Notes

  • Automatically starts the timeout when delay changes (if delay is not null)
  • Setting delay to null disables the timeout
  • Properly cleans up timeouts on unmount to prevent memory leaks
  • The callback ref is updated on each render to ensure latest closure
  • Provides both automatic and manual control over timeout execution
  • Also exports useTimeoutEffect for simpler automatic timeout behavior

Implementation

1"use client"; 2 3import { useEffect, useRef, useCallback } from "react"; 4 5export interface UseTimeoutReturn { 6 start: () => void; 7 stop: () => void; 8 reset: () => void; 9 isActive: () => boolean; 10} 11 12export function useTimeout( 13 callback: () => void, 14 delay: number | null 15): UseTimeoutReturn { 16 const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null); 17 const callbackRef = useRef(callback); 18 19 // Update callback ref when callback changes 20 useEffect(() => { 21 callbackRef.current = callback; 22 }, [callback]); 23 24 const start = useCallback(() => { 25 // Clear existing timeout 26 if (timeoutRef.current) { 27 clearTimeout(timeoutRef.current); 28 } 29 30 // Only set timeout if delay is not null 31 if (delay !== null) { 32 timeoutRef.current = setTimeout(() => { 33 callbackRef.current(); 34 timeoutRef.current = null; 35 }, delay); 36 } 37 }, [delay]); 38 39 const stop = useCallback(() => { 40 if (timeoutRef.current) { 41 clearTimeout(timeoutRef.current); 42 timeoutRef.current = null; 43 } 44 }, []); 45 46 const reset = useCallback(() => { 47 stop(); 48 start(); 49 }, [stop, start]); 50 51 const isActive = useCallback(() => { 52 return timeoutRef.current !== null; 53 }, []); 54 55 // Auto-start timeout when delay changes (if delay is not null) 56 useEffect(() => { 57 if (delay !== null) { 58 start(); 59 } else { 60 stop(); 61 } 62 63 // Cleanup on unmount or when delay changes 64 return stop; 65 }, [delay, start, stop]); 66 67 return { start, stop, reset, isActive }; 68} 69 70// Simplified version that just runs the timeout automatically 71export function useTimeoutEffect( 72 callback: () => void, 73 delay: number | null 74): void { 75 const callbackRef = useRef(callback); 76 77 // Update callback ref when callback changes 78 useEffect(() => { 79 callbackRef.current = callback; 80 }, [callback]); 81 82 useEffect(() => { 83 if (delay === null) { 84 return; 85 } 86 87 const timeoutId = setTimeout(() => { 88 callbackRef.current(); 89 }, delay); 90 91 return () => clearTimeout(timeoutId); 92 }, [delay]); 93} 94