50 lines
1.2 KiB
JavaScript
50 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 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;
|
||
|
}
|
||
|
}, [value]);
|
||
|
|
||
|
useUnmount(() => {
|
||
|
timeout.current && clearTimeout(timeout.current);
|
||
|
});
|
||
|
|
||
|
return state;
|
||
|
}
|
||
|
|
||
|
export default useThrottle;
|