Delay a state update. Very handy for animations and other UI effects.
0
1 second delay
0
Conditional delay (2s for count ≥ 5)
0
Installation
Copy and paste the following code into your project.
'use client';
import { useEffect, useRef, useState } from 'react';
export function useFnDelay<T>(
asyncFactory: (delay: (timeMs: number) => Promise<void>) => Promise<T>,
deps: React.DependencyList
) {
const [value, setValue] = useState<T | null>(null);
const abortControllerRef = useRef<AbortController | null>(null);
useEffect(() => {
// Abort previous async operation
if (abortControllerRef.current) {
abortControllerRef.current.abort();
}
// Create new abort controller for this operation
abortControllerRef.current = new AbortController();
const currentAbortController = abortControllerRef.current;
// Create the delay function that returns a promise
const delayFn = (timeMs: number): Promise<void> => {
return new Promise((resolve, reject) => {
const timeoutId = setTimeout(() => {
if (!currentAbortController.signal.aborted) {
resolve();
}
}, timeMs);
// Handle abortion
currentAbortController.signal.addEventListener('abort', () => {
clearTimeout(timeoutId);
reject(new Error('Delay aborted'));
});
});
};
// Execute the async factory function
const executeFactory = async () => {
try {
const result = await asyncFactory(delayFn);
// Only update if not aborted
if (!currentAbortController.signal.aborted) {
setValue(result);
}
} catch (error) {
// Ignore abortion errors, but log others
if (error instanceof Error && error.message !== 'Delay aborted') {
console.error('Error in useFnDelay factory:', error);
}
}
};
executeFactory();
// Cleanup function
return () => {
if (currentAbortController) {
currentAbortController.abort();
}
};
}, deps);
// Cleanup on unmount
useEffect(() => {
return () => {
if (abortControllerRef.current) {
abortControllerRef.current.abort();
}
};
}, []);
return value;
}
// Simpler hook built on top of useFnDelay
export function useDelay<T>(value: T, delayMs: number) {
return useFnDelay(
async (delay: (timeMs: number) => Promise<void>) => {
if (delayMs > 0) {
await delay(delayMs);
}
return value;
},
[value, delayMs]
);
}
Update the import paths to match your project setup.
Usage
import { useDelay, useFnDelay } from '@kit/ui/hooks/use-delay';
const [count, setCount] = useState(0);
const delayedCount = useDelay(count, 1000);
// function approach
const conditionalDelayResult = useFnDelay(
async (delay) => {
if (count < 5) return count;
await delay(2000);
return count;
},
[count]
);
API Reference
useDelay
Takes : <T>(value: T, delayMs: number) => T
useFnDelay
Takes :
<T>(
asyncFactory: (delay: (timeMs: number) => Promise<void>) => Promise<T>,
deps: React.DependencyList
) => T
Use Copy To Clipboard
A simple hook to copy to clipboard.
Input Drag Control
Update a number using drag controls
How is this guide?
Last updated on 10/17/2025