47 lines
1.2 KiB
JavaScript
47 lines
1.2 KiB
JavaScript
// @flow
|
|
import React from 'react';
|
|
|
|
const useEffectOnce = (effect) => {
|
|
React.useEffect(effect, []);
|
|
};
|
|
|
|
function useUnmount(fn: () => any): void {
|
|
const fnRef = React.useRef(fn);
|
|
|
|
// update the ref each render so if it change the newest callback will be invoked
|
|
fnRef.current = fn;
|
|
|
|
useEffectOnce(() => () => fnRef.current());
|
|
}
|
|
|
|
export default function useThrottle(value: string, ms: number = 200) {
|
|
const [state, setState] = React.useState(value);
|
|
const timeout = React.useRef();
|
|
const nextValue = React.useRef(null);
|
|
const hasNextValue = React.useRef(0);
|
|
|
|
React.useEffect(() => {
|
|
if (!timeout.current) {
|
|
setState(value);
|
|
const timeoutCallback = () => {
|
|
if (hasNextValue.current) {
|
|
hasNextValue.current = false;
|
|
setState(nextValue.current);
|
|
timeout.current = setTimeout(timeoutCallback, ms);
|
|
} else {
|
|
timeout.current = undefined;
|
|
}
|
|
};
|
|
timeout.current = setTimeout(timeoutCallback, ms);
|
|
} else {
|
|
nextValue.current = value;
|
|
hasNextValue.current = true;
|
|
}
|
|
}, [ms, value]);
|
|
|
|
useUnmount(() => {
|
|
timeout.current && clearTimeout(timeout.current);
|
|
});
|
|
|
|
return state;
|
|
}
|