Hook Proposal: useTimeoutControlledFn ā a manual version of useTimeoutFn
useTimeoutFn, starts the timeout automatically on mount. In our case, we needed something similar but fully manual which is a timeout only starts when we explicitly trigger it (e.g., after an API success).
Why this might be useful
- No automatic timeout on mount
- Full control:
start(),cancel(),reset() - Ability to reuse the last delay (
reset) - Useful in callbacks, controlled UI flows, etc.
API
const [isReady, cancel, start, reset] = useTimeoutControlledFn(fn, defaultMs?: number);
-
isReady()ā returnstrue | false | null -
cancel()ā cancels the current timeout -
start(delay?)ā starts a new timeout -
reset()ā reuses last delay
Example
const [isReady, cancel, start, reset] = useTimeoutControlledFn(() => {
console.log('Executed after delay!');
}, 1500);
// Manually start after a successful API call
const onApiSuccess = () => start();
If this sounds useful, Iām happy to prepare a full PR with tests and docs. Just wanted to get your feedback first
Also (maybe?) if useTimeoutControlledFn is introduced, it could be reused internally by both useTimeoutFn and useTimeout to simplify the implementation and keep things consistent.
For example:
// useTimeout.ts
import useTimeoutFn from './useTimeoutFn';
import useUpdate from './useUpdate';
export default function useTimeout(ms: number = 0) {
const update = useUpdate();
return useTimeoutFn(update, ms);
}
// useTimeoutFn.ts
import useTimeoutControlledFn from './useTimeoutControlledFn';
export default function useTimeoutFn(fn: Function, ms: number = 0) {
const [isReady, cancel, start] = useTimeoutControlledFn(fn, ms);
useEffect(() => {
start();
return cancel;
}, [ms]);
return [isReady, cancel, start];
}
So even though it's a new hook, it could act as the base logic and reduce duplication across the others. Let me know if that sounds good. Iād be happy to refactor and include those changes in a PR as well.