Skip to content

Instantly share code, notes, and snippets.

@luismartinezs
Last active August 30, 2022 10:01
Show Gist options
  • Save luismartinezs/e2baaebf400d5da27f28409e699a2489 to your computer and use it in GitHub Desktop.
Save luismartinezs/e2baaebf400d5da27f28409e699a2489 to your computer and use it in GitHub Desktop.
React useImperativeTimeout #react #hooks
// https://blog.thoughtspile.tech/2021/10/13/really-declarative/
import React, { useRef, useEffect, useCallback, useState } from 'react';
function useImperativeTimeout(callback, delay) {
const timeoutId = useRef(null);
const savedCallback = useRef();
// Remember the latest callback.
useEffect(() => {
savedCallback.current = callback;
}, [callback]);
// this handle clears the timeout
const clear = useCallback(() => {
clearTimeout(timeoutId.current);
}, []);
// this handle sets our timeout
const set = useCallback(() => {
// but clears the old one first
clear();
timeoutId.current = setTimeout(() => {
savedCallback.current();
}, delay);
}, [delay]);
// also, clear the timeout on unmount
useEffect(() => clear, []);
return { set, clear };
}
// Usage example
const Input = ({ details }) => {
const [showDetails, setShowDetails] = useState(false);
const showTimeout = useImperativeTimeout(() => {
setShowDetails(true);
}, 100);
const onEnter = showTimeout.set;
const onLeave = () => {
showTimeout.clear();
setShowDeatils(false);
};
return (
<div>
<input />
<span
onMouseEnter={onEnter}
onMouseLeave={onLeave}
>i</span>
</div>
);
};
// Declarative timeout, built on top of our imperative timeout
function useWrapTimeout(callback, delay) {
const handle = useImperativeTimeout(callback, delay);
useEffect(() => {
if (delay != null) {
handle.set();
return handle.clear;
}
}, [delay]);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment