mirror of
https://github.com/streamich/react-use.git
synced 2026-01-18 14:06:52 +00:00
Merge pull request #568 from streamich/imp-useTimeout
fix: make useTimeoutFn work properly:
This commit is contained in:
commit
d5ca05e231
@ -1,10 +1,13 @@
|
||||
# `useTimeoutFn`
|
||||
|
||||
Calls given function after specified amount of milliseconds.
|
||||
**Note:** this hook does not re-render component by itself.
|
||||
Calls given function after specified amount of milliseconds.
|
||||
|
||||
Automatically cancels timeout on component unmount.
|
||||
Automatically resets timeout on delay change.
|
||||
Several thing about it's work:
|
||||
- does not re-render component;
|
||||
- automatically cancel timeout on cancel;
|
||||
- automatically reset timeout on delay change;
|
||||
- reset function call will cancel previous timeout;
|
||||
- timeout will NOT be reset on function change. It will be called within the timeout, you have to reset it on your own when needed.
|
||||
|
||||
## Usage
|
||||
|
||||
|
||||
@ -28,9 +28,11 @@ describe('useTimeoutFn', () => {
|
||||
expect(typeof hook.result.current[2]).toBe('function');
|
||||
});
|
||||
|
||||
function getHook(ms: number = 5): [jest.Mock, RenderHookResult<{ delay: number }, UseTimeoutFnReturn>] {
|
||||
const spy = jest.fn();
|
||||
return [spy, renderHook(({ delay = 5 }) => useTimeoutFn(spy, delay), { initialProps: { delay: ms } })];
|
||||
function getHook(
|
||||
ms: number = 5,
|
||||
fn: Function = jest.fn()
|
||||
): [Function, RenderHookResult<{ delay: number; cb: Function }, UseTimeoutFnReturn>] {
|
||||
return [fn, renderHook(({ delay = 5, cb }) => useTimeoutFn(cb, delay), { initialProps: { delay: ms, cb: fn } })];
|
||||
}
|
||||
|
||||
it('should call passed function after given amount of time', () => {
|
||||
@ -108,9 +110,23 @@ describe('useTimeoutFn', () => {
|
||||
const [spy, hook] = getHook(50);
|
||||
|
||||
expect(spy).not.toHaveBeenCalled();
|
||||
hook.rerender({ delay: 5 });
|
||||
hook.rerender({ delay: 5, cb: spy });
|
||||
|
||||
jest.advanceTimersByTime(5);
|
||||
expect(spy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should NOT reset timeout on function change', () => {
|
||||
const [spy, hook] = getHook(50);
|
||||
|
||||
jest.advanceTimersByTime(25);
|
||||
expect(spy).not.toHaveBeenCalled();
|
||||
|
||||
const spy2 = jest.fn();
|
||||
hook.rerender({ delay: 50, cb: spy2 });
|
||||
|
||||
jest.advanceTimersByTime(25);
|
||||
expect(spy).not.toHaveBeenCalled();
|
||||
expect(spy2).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
@ -5,20 +5,31 @@ export type UseTimeoutFnReturn = [() => boolean | null, () => void, () => void];
|
||||
export default function useTimeoutFn(fn: Function, ms: number = 0): UseTimeoutFnReturn {
|
||||
const ready = useRef<boolean | null>(false);
|
||||
const timeout = useRef<ReturnType<typeof setTimeout>>();
|
||||
const callback = useRef(fn);
|
||||
|
||||
const isReady = useCallback(() => ready.current, []);
|
||||
|
||||
const set = useCallback(() => {
|
||||
ready.current = false;
|
||||
timeout.current && clearTimeout(timeout.current);
|
||||
|
||||
timeout.current = setTimeout(() => {
|
||||
ready.current = true;
|
||||
fn();
|
||||
callback.current();
|
||||
}, ms);
|
||||
}, [ms, fn]);
|
||||
}, [ms]);
|
||||
|
||||
const clear = useCallback(() => {
|
||||
ready.current = null;
|
||||
timeout.current && clearTimeout(timeout.current);
|
||||
}, []);
|
||||
|
||||
// update ref when function changes
|
||||
useEffect(() => {
|
||||
callback.current = fn;
|
||||
}, [fn]);
|
||||
|
||||
// set on mount, clear on unmount
|
||||
useEffect(() => {
|
||||
set();
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user