Skip to content

Instantly share code, notes, and snippets.

@amochkin
Last active November 2, 2022 20:52
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 amochkin/bbd509670018d508ed976ddd1f594935 to your computer and use it in GitHub Desktop.
Save amochkin/bbd509670018d508ed976ddd1f594935 to your computer and use it in GitHub Desktop.
import { useEffect, useRef, useState } from 'react';
type TimerCallbackType = (timerLeft: number) => void;
/**
* useTimer hook to handle timer events. Has protection from subsequent calls, ie calling the timer when it was already started.
* @param callback Callback function
* @param timer Timer in milliseconds
* @param interval Interval between timer ticks in milliseconds
*/
export const useTimer = (callback: TimerCallbackType, timer: number, interval: number = 1000) => {
const savedCallback = useRef<TimerCallbackType>();
const [isActive, setIsActive] = useState<boolean>(false);
useEffect(() => {
savedCallback.current = callback;
});
useEffect(() => {
function tick(left: number) {
const nextLeft = left - interval;
if (nextLeft >= interval) {
savedCallback.current && savedCallback.current(nextLeft);
setTimeout(() => tick(nextLeft), interval);
} else {
savedCallback.current && savedCallback.current(0);
setIsActive(false);
}
}
if (!isActive) {
setIsActive(true);
tick(timer);
}
// isActive is not a dependency because we don't want to restart the timer when it changes,
// so we disable the warning on the next line:
}, [interval, timer]); // eslint-disable-line react-hooks/exhaustive-deps
};
@amochkin
Copy link
Author

amochkin commented Nov 2, 2022

Example:

export const Component:React.FC<{}> = () => {
	const [timer, setTimer] = React.useState<number>(0);

	useTimer(timerLeft => {
		setTimer(timerLeft / 1000);
	}, timer * 1000);

	const handleTimerStart = () => {
		if (timer === 0) {
			setTimer(10 * 1000); // set for 10 seconds
		}
	};

	return (
		<TouchableOpacity onPress={timer === 0 ? handleTimerStart : () => null}>
			<Text>
				{timer !== 0 ? `${timer}s` : 'Press me'}
			</Text>
		</TouchableOpacity>
	);
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment