Skip to content

Instantly share code, notes, and snippets.

@cgarrovillo
Created March 22, 2024 17:09
Show Gist options
  • Save cgarrovillo/545e5c39075fe40dd950264c76ec2f8e to your computer and use it in GitHub Desktop.
Save cgarrovillo/545e5c39075fe40dd950264c76ec2f8e to your computer and use it in GitHub Desktop.
useInterval with watched returns
import { useEffect, useMemo, useRef } from "react";
type UseIntervalTypes = {
callback: () => void;
delay: number;
};
/**
* React lifecycle-aware implementation of setInterval.
* This allows for a quick implementation of setInterval in React without having to worry about cleanup.
* @see https://overreacted.io/making-setinterval-declarative-with-react-hooks/ by Dan Abramov for more details.
*/
function useInterval(
callback: UseIntervalTypes["callback"],
delay: UseIntervalTypes["delay"]
) {
const runOnMount = useRef<boolean>(true);
const savedCallback = useRef<UseIntervalTypes["callback"]>();
const intervalRef = useRef<NodeJS.Timeout>();
useEffect(() => {
return () => {
if (intervalRef.current) clearInterval(intervalRef.current);
};
}, []);
// Remember the latest callback.
useEffect(() => {
savedCallback.current = callback;
}, [callback]);
// Run the interval if this hook mounts and runOnMount is true
// eslint-disable-next-line consistent-return
useEffect(() => {
function tick() {
savedCallback.current?.();
}
if (delay !== null && runOnMount.current) {
intervalRef.current = setInterval(tick, delay);
}
}, [delay]);
// Run the interval when this function is called
const beginPolling = () => {
function tick() {
savedCallback.current?.();
}
intervalRef.current = setInterval(tick, delay);
};
// Intercept how this function is called
const interceptedReturn = useMemo(() => {
return new Proxy([beginPolling], {
get(target, prop, receiver) {
// If beginPolling is extracted on the call (ie. const [poll] = useInterval(_, 5000)),
// do not start the interval on mount.
if (!Number.isNaN(prop) && prop === "0") {
runOnMount.current = false;
}
return Reflect.get(target, prop, receiver);
},
});
}, [beginPolling]);
return interceptedReturn;
}
export default useInterval;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment