Hooks
No hooks found in any category.
useTimeout
utilitiesInstallation
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
Name | Type | Default | Description |
---|---|---|---|
callback | () => void | - | The function to execute when the timeout completes |
delay | number | null | - | The delay in milliseconds, or null to disable the timeout |
Return Type
UseTimeoutReturn
Property | Type | Description |
---|---|---|
start | () => void | Starts or restarts the timeout |
stop | () => void | Stops the timeout and prevents the callback from executing |
reset | () => void | Stops the current timeout and starts a new one |
isActive | () => boolean | Returns 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