Skip to content

Instantly share code, notes, and snippets.

@erkobridee
Last active April 27, 2020 09:51
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 erkobridee/0634a699173f9582a3ef072d90ce7ec1 to your computer and use it in GitHub Desktop.
Save erkobridee/0634a699173f9582a3ef072d90ce7ec1 to your computer and use it in GitHub Desktop.
safe way to use setTimeout or setInterval through react hooks
import * as React from 'react';
export enum JSTypeof {
UNDEFINED = 'undefined',
FUNCTION = 'function',
OBJECT = 'object',
STRING = 'string',
NUMBER = 'number',
}
export const isNumber = <T extends number>(value: any): value is T =>
value !== null && typeof value === JSTypeof.NUMBER;
export type TFunction<Tuple extends any[] = any[], Return = any> = (
...args: Tuple
) => Return;
export interface IUserWaitOptions {
callback: TFunction;
delay: number;
autorun?: boolean;
waitFunction?: TFunction;
cleanWaitFunction?: TFunction;
}
/**
* common wait hook code for window.setTimeout or window.setInterval
*
* @param {IUserWaitOptions} options
*/
export const useWait: TFunction<[IUserWaitOptions], [TFunction, TFunction]> = ({
callback,
delay,
autorun = true,
waitFunction = window.setTimeout,
cleanWaitFunction = window.clearTimeout,
}) => {
const savedCallback = React.useRef<TFunction>(callback);
const waitRef = React.useRef<number | undefined>(undefined);
const startWait = React.useCallback(() => {
if (waitRef.current || !isNumber(delay) || delay < 0) {
return;
}
const runOnWait = () => {
savedCallback.current();
waitRef.current = undefined;
};
waitRef.current = waitFunction(runOnWait, delay);
}, [delay, waitFunction]);
const clearWait = React.useCallback(() => {
if (!waitRef.current) {
return;
}
cleanWaitFunction(waitRef.current);
waitRef.current = undefined;
}, [cleanWaitFunction]);
React.useEffect(() => {
savedCallback.current = callback;
}, [callback]);
React.useEffect(() => {
if (autorun) {
clearWait();
startWait();
}
return () => clearWait();
}, [delay, autorun, clearWait, startWait]);
return [startWait, clearWait];
};
/**
* safe way to use window.setTimeout using a hook to handle it
*
* @param {TFunction} callback to be executed by the timeout
* @param {number} delay time to the execution
* @param {boolean} autorun flag that says if should start running right after call the hook - default true
*
* @return {[TFunction, TFunction]} start and clear functions
*/
export const useTimeout = (
callback: TFunction,
delay: number,
autorun: boolean = true
): [TFunction, TFunction] => {
return useWait({ callback, delay, autorun });
};
/**
* safe way to use window.setInterval using a hook to handle it
*
* @param {TFunction} callback to be executed on each interval
* @param {number} delay time between the executions
* @param {boolean} autorun flag that says if should start running right after call the hook - default true
*
* @return {[TFunction, TFunction]} start and stop functions
*/
export const useInterval = (
callback: TFunction,
delay: number,
autorun: boolean = true
): [TFunction, TFunction] => {
return useWait({
callback,
delay,
autorun,
waitFunction: window.setInterval,
cleanWaitFunction: window.clearInterval,
});
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment