Skip to content

Instantly share code, notes, and snippets.

@donaldpipowitch
Created October 6, 2021 07:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save donaldpipowitch/6f15d90ec964936d3011b9b594be80cc to your computer and use it in GitHub Desktop.
Save donaldpipowitch/6f15d90ec964936d3011b9b594be80cc to your computer and use it in GitHub Desktop.
use-timeout.ts
// it's like setTimeout as a hook, but with a small twist:
// you can make multiple subsequent calls and can increase or decrease
// the delay (e.g. useful to create polling like functionality)
type Options = {
delay: number;
multiplier?: number;
};
type State = {
running: boolean;
count: number;
delay: number;
callback?: Function;
};
function useTimeout(options: Options) {
const initialDelay = options.delay;
const multiplier = options.multiplier ?? 1;
const initialState = useMemo<State>(
() => ({
running: false,
count: 0,
delay: initialDelay,
}),
[initialDelay]
);
const [state, setState] = useState<State>(initialState);
useEffect(() => {
if (!state.count) return;
const timeoutId = setTimeout(() => {
setState((state) => ({
...state,
running: false,
delay: state.delay * multiplier,
}));
state.callback?.();
}, state.delay);
return () => clearTimeout(timeoutId);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [state.count]);
const next = useCallback(
(callback: Function) =>
setState((state) => ({
...state,
running: true,
count: state.count + 1,
callback,
})),
[]
);
const reset = useCallback(() => setState(initialState), [initialState]);
const { running, count, delay } = state;
const value = useMemo(
() => ({ count, delay, next, reset, running }),
[count, delay, next, reset, running]
);
return value;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment