Last active
April 27, 2020 09:51
-
-
Save erkobridee/0634a699173f9582a3ef072d90ce7ec1 to your computer and use it in GitHub Desktop.
safe way to use setTimeout or setInterval through react hooks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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