mirror of
https://github.com/streamich/react-use.git
synced 2026-01-25 14:17:16 +00:00
Merge branch 'original-master' into animation-block-tests
# Conflicts: # src/__tests__/useTimeout.test.ts
This commit is contained in:
commit
5c50ad39da
13
CHANGELOG.md
13
CHANGELOG.md
@ -1,3 +1,16 @@
|
||||
# [11.0.0](https://github.com/streamich/react-use/compare/v10.8.0...v11.0.0) (2019-08-22)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add cancel and reset methods to useTimeout ([283045a](https://github.com/streamich/react-use/commit/283045a))
|
||||
* add useTimeoutFn ([284e6fd](https://github.com/streamich/react-use/commit/284e6fd))
|
||||
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* useTimeout now returns a tuple
|
||||
|
||||
# [10.8.0](https://github.com/streamich/react-use/compare/v10.7.1...v10.8.0) (2019-08-20)
|
||||
|
||||
|
||||
|
||||
@ -81,7 +81,8 @@
|
||||
- [`useRaf`](./docs/useRaf.md) — re-renders component on each `requestAnimationFrame`.
|
||||
- [`useInterval`](./docs/useInterval.md) — re-renders component on a set interval using `setInterval`.
|
||||
- [`useSpring`](./docs/useSpring.md) — interpolates number over time according to spring dynamics.
|
||||
- [`useTimeout`](./docs/useTimeout.md) — returns true after a timeout.
|
||||
- [`useTimeout`](./docs/useTimeout.md) — re-renders component after a timeout.
|
||||
- [`useTimeoutFn`](./docs/useTimeoutFn.md) — calls given function after a timeout. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/animation-usetimeoutfn--demo)
|
||||
- [`useTween`](./docs/useTween.md) — re-renders component, while tweening a number from 0 to 1. [![][img-demo]](https://codesandbox.io/s/52990wwzyl)
|
||||
- [`useUpdate`](./docs/useUpdate.md) — returns a callback, which re-renders component when called.
|
||||
<br/>
|
||||
|
||||
@ -1,15 +1,48 @@
|
||||
# `useTimeout`
|
||||
|
||||
Returns `true` after a specified number of milliseconds.
|
||||
Re-renders the component after a specified number of milliseconds.
|
||||
Provides handles to cancel and/or reset the timeout.
|
||||
|
||||
## Usage
|
||||
|
||||
```jsx
|
||||
import { useTimeout } from 'react-use';
|
||||
|
||||
const Demo = () => {
|
||||
const ready = useTimeout(2000);
|
||||
function TestComponent(props: { ms?: number } = {}) {
|
||||
const ms = props.ms || 5000;
|
||||
const [isReady, cancel] = useTimeout(ms);
|
||||
|
||||
return <div>Ready: {ready ? 'Yes' : 'No'}</div>;
|
||||
return (
|
||||
<div>
|
||||
{ isReady() ? 'I\'m reloaded after timeout' : `I will be reloaded after ${ ms / 1000 }s` }
|
||||
{ isReady() === false ? <button onClick={ cancel }>Cancel</button> : '' }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const Demo = () => {
|
||||
return (
|
||||
<div>
|
||||
<TestComponent />
|
||||
<TestComponent ms={ 10000 } />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
## Reference
|
||||
|
||||
```ts
|
||||
const [
|
||||
isReady: () => boolean | null,
|
||||
cancel: () => void,
|
||||
reset: () => void,
|
||||
] = useTimeout(ms: number = 0);
|
||||
```
|
||||
|
||||
- **`isReady`**_` :()=>boolean|null`_ - function returning current timeout state:
|
||||
- `false` - pending re-render
|
||||
- `true` - re-render performed
|
||||
- `null` - re-render cancelled
|
||||
- **`cancel`**_` :()=>void`_ - cancel the timeout (component will not be re-rendered)
|
||||
- **`reset`**_` :()=>void`_ - reset the timeout
|
||||
|
||||
65
docs/useTimeoutFn.md
Normal file
65
docs/useTimeoutFn.md
Normal file
@ -0,0 +1,65 @@
|
||||
# `useTimeoutFn`
|
||||
|
||||
Calls given function after specified amount of milliseconds.
|
||||
**Note:** this hook does not re-render component by itself.
|
||||
|
||||
Automatically cancels timeout on component unmount.
|
||||
Automatically resets timeout on delay change.
|
||||
|
||||
## Usage
|
||||
|
||||
```jsx
|
||||
import * as React from 'react';
|
||||
import { useTimeoutFn } from 'react-use';
|
||||
|
||||
const Demo = () => {
|
||||
const [state, setState] = React.useState('Not called yet');
|
||||
|
||||
function fn() {
|
||||
setState(`called at ${Date.now()}`);
|
||||
}
|
||||
|
||||
const [isReady, cancel, reset] = useTimeoutFn(fn, 5000);
|
||||
const cancelButtonClick = useCallback(() => {
|
||||
if (isReady() === false) {
|
||||
cancel();
|
||||
setState(`cancelled`);
|
||||
} else {
|
||||
reset();
|
||||
setState('Not called yet');
|
||||
}
|
||||
}, []);
|
||||
|
||||
const readyState = isReady();
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div>{readyState !== null ? 'Function will be called in 5 seconds' : 'Timer cancelled'}</div>
|
||||
<button onClick={cancelButtonClick}> {readyState === false ? 'cancel' : 'restart'} timeout</button>
|
||||
<br />
|
||||
<div>Function state: {readyState === false ? 'Pending' : readyState ? 'Called' : 'Cancelled'}</div>
|
||||
<div>{state}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
## Reference
|
||||
|
||||
```ts
|
||||
const [
|
||||
isReady: () => boolean | null,
|
||||
cancel: () => void,
|
||||
reset: () => void,
|
||||
] = useTimeoutFn(fn: Function, ms: number = 0);
|
||||
```
|
||||
|
||||
- **`fn`**_`: Function`_ - function that will be called;
|
||||
- **`ms`**_`: number`_ - delay in milliseconds;
|
||||
- **`isReady`**_`: ()=>boolean|null`_ - function returning current timeout state:
|
||||
- `false` - pending
|
||||
- `true` - called
|
||||
- `null` - cancelled
|
||||
- **`cancel`**_`: ()=>void`_ - cancel the timeout
|
||||
- **`reset`**_`: ()=>void`_ - reset the timeout
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-use",
|
||||
"version": "10.8.0",
|
||||
"version": "11.0.0",
|
||||
"description": "Collection of React Hooks",
|
||||
"main": "lib/index.js",
|
||||
"module": "esm/index.js",
|
||||
@ -96,7 +96,7 @@
|
||||
"redux-thunk": "2.3.0",
|
||||
"rimraf": "3.0.0",
|
||||
"rxjs": "6.5.2",
|
||||
"semantic-release": "15.13.21",
|
||||
"semantic-release": "15.13.24",
|
||||
"ts-loader": "6.0.4",
|
||||
"ts-node": "8.3.0",
|
||||
"tslint": "5.19.0",
|
||||
|
||||
@ -3,10 +3,25 @@ import * as React from 'react';
|
||||
import { useTimeout } from '..';
|
||||
import ShowDocs from './util/ShowDocs';
|
||||
|
||||
const Demo = () => {
|
||||
const ready = useTimeout(2e3);
|
||||
function TestComponent(props: { ms?: number } = {}) {
|
||||
const ms = props.ms || 5000;
|
||||
const [isReady, cancel] = useTimeout(ms);
|
||||
|
||||
return <div>Ready: {ready ? 'Yes' : 'No'}</div>;
|
||||
return (
|
||||
<div>
|
||||
{isReady() ? "I'm reloaded after timeout" : `I will be reloaded after ${ms / 1000}s`}
|
||||
{isReady() === false ? <button onClick={cancel}>Cancel</button> : ''}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const Demo = () => {
|
||||
return (
|
||||
<div>
|
||||
<TestComponent />
|
||||
<TestComponent ms={10000} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
storiesOf('Animation|useTimeout', module)
|
||||
|
||||
40
src/__stories__/useTimeoutFn.story.tsx
Normal file
40
src/__stories__/useTimeoutFn.story.tsx
Normal file
@ -0,0 +1,40 @@
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import * as React from 'react';
|
||||
import { useCallback } from 'react';
|
||||
import { useTimeoutFn } from '../index';
|
||||
import ShowDocs from './util/ShowDocs';
|
||||
|
||||
const Demo = () => {
|
||||
const [state, setState] = React.useState('Not called yet');
|
||||
|
||||
function fn() {
|
||||
setState(`called at ${Date.now()}`);
|
||||
}
|
||||
|
||||
const [isReady, cancel, reset] = useTimeoutFn(fn, 5000);
|
||||
const cancelButtonClick = useCallback(() => {
|
||||
if (isReady() === false) {
|
||||
cancel();
|
||||
setState(`cancelled`);
|
||||
} else {
|
||||
reset();
|
||||
setState('Not called yet');
|
||||
}
|
||||
}, []);
|
||||
|
||||
const readyState = isReady();
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div>{readyState !== null ? 'Function will be called in 5 seconds' : 'Timer cancelled'}</div>
|
||||
<button onClick={cancelButtonClick}> {readyState === false ? 'cancel' : 'restart'} timeout</button>
|
||||
<br />
|
||||
<div>Function state: {readyState === false ? 'Pending' : readyState ? 'Called' : 'Cancelled'}</div>
|
||||
<div>{state}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
storiesOf('Animation|useTimeoutFn', module)
|
||||
.add('Docs', () => <ShowDocs md={require('../../docs/useTimeoutFn.md')} />)
|
||||
.add('Demo', () => <Demo />);
|
||||
@ -1,83 +1,138 @@
|
||||
import { act, renderHook } from '@testing-library/react-hooks';
|
||||
import useTimeout from '../useTimeout';
|
||||
import { act, renderHook, RenderHookResult } from '@testing-library/react-hooks';
|
||||
import { useTimeout } from '../index';
|
||||
import { UseTimeoutReturn } from '../useTimeout';
|
||||
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllTimers();
|
||||
});
|
||||
|
||||
it('should init ready bool to false', () => {
|
||||
const { result } = renderHook(() => useTimeout());
|
||||
|
||||
expect(result.current).toBe(false);
|
||||
});
|
||||
|
||||
it('should return ready as true on default timeout reached', () => {
|
||||
const { result } = renderHook(() => useTimeout());
|
||||
|
||||
act(() => {
|
||||
// default timeout is 0 so we just basically start running scheduled timer
|
||||
jest.advanceTimersByTime(0);
|
||||
describe('useTimeout', () => {
|
||||
beforeAll(() => {
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
expect(result.current).toBe(true);
|
||||
});
|
||||
|
||||
it('should return ready as true on custom timeout reached', () => {
|
||||
const { result } = renderHook(() => useTimeout(200));
|
||||
|
||||
act(() => {
|
||||
jest.advanceTimersByTime(200);
|
||||
});
|
||||
|
||||
expect(result.current).toBe(true);
|
||||
});
|
||||
|
||||
it('should always return ready as false on custom timeout not reached', () => {
|
||||
const { result } = renderHook(() => useTimeout(200));
|
||||
|
||||
act(() => {
|
||||
jest.advanceTimersByTime(100);
|
||||
});
|
||||
expect(result.current).toBe(false);
|
||||
|
||||
act(() => {
|
||||
jest.advanceTimersByTime(90);
|
||||
});
|
||||
expect(result.current).toBe(false);
|
||||
|
||||
act(() => {
|
||||
jest.advanceTimersByTime(9);
|
||||
});
|
||||
expect(result.current).toBe(false);
|
||||
});
|
||||
|
||||
it('should always return ready as true after custom timeout reached', () => {
|
||||
const { result } = renderHook(() => useTimeout(200));
|
||||
|
||||
act(() => {
|
||||
jest.advanceTimersByTime(200);
|
||||
});
|
||||
expect(result.current).toBe(true);
|
||||
|
||||
act(() => {
|
||||
jest.advanceTimersByTime(20);
|
||||
});
|
||||
expect(result.current).toBe(true);
|
||||
|
||||
act(() => {
|
||||
jest.advanceTimersByTime(100);
|
||||
});
|
||||
expect(result.current).toBe(true);
|
||||
});
|
||||
|
||||
it('should clear pending timer on unmount', () => {
|
||||
const { unmount } = renderHook(() => useTimeout());
|
||||
expect(jest.getTimerCount()).toBe(1);
|
||||
|
||||
unmount();
|
||||
expect(jest.getTimerCount()).toBe(0);
|
||||
afterEach(() => {
|
||||
jest.clearAllTimers();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(useTimeout).toBeDefined();
|
||||
});
|
||||
|
||||
it('should return three functions', () => {
|
||||
const hook = renderHook(() => useTimeout(5));
|
||||
|
||||
expect(hook.result.current.length).toBe(3);
|
||||
expect(typeof hook.result.current[0]).toBe('function');
|
||||
expect(typeof hook.result.current[1]).toBe('function');
|
||||
expect(typeof hook.result.current[2]).toBe('function');
|
||||
});
|
||||
|
||||
function getHook(ms: number = 5): [jest.Mock, RenderHookResult<{ delay: number }, UseTimeoutReturn>] {
|
||||
const spy = jest.fn();
|
||||
return [
|
||||
spy,
|
||||
renderHook(
|
||||
({ delay = 5 }) => {
|
||||
spy();
|
||||
return useTimeout(delay);
|
||||
},
|
||||
{ initialProps: { delay: ms } }
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
it('should re-render component after given amount of time', done => {
|
||||
const [spy, hook] = getHook();
|
||||
expect(spy).toHaveBeenCalledTimes(1);
|
||||
hook.waitForNextUpdate().then(() => {
|
||||
expect(spy).toHaveBeenCalledTimes(2);
|
||||
done();
|
||||
});
|
||||
jest.advanceTimersByTime(5);
|
||||
});
|
||||
|
||||
it('should cancel timeout on unmount', () => {
|
||||
const [spy, hook] = getHook();
|
||||
|
||||
expect(spy).toHaveBeenCalledTimes(1);
|
||||
hook.unmount();
|
||||
jest.advanceTimersByTime(5);
|
||||
expect(spy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('first function should return actual state of timeout', done => {
|
||||
let [, hook] = getHook();
|
||||
let [isReady] = hook.result.current;
|
||||
|
||||
expect(isReady()).toBe(false);
|
||||
hook.unmount();
|
||||
expect(isReady()).toBe(null);
|
||||
|
||||
[, hook] = getHook();
|
||||
[isReady] = hook.result.current;
|
||||
hook.waitForNextUpdate().then(() => {
|
||||
expect(isReady()).toBe(true);
|
||||
|
||||
done();
|
||||
});
|
||||
jest.advanceTimersByTime(5);
|
||||
});
|
||||
|
||||
it('second function should cancel timeout', () => {
|
||||
const [spy, hook] = getHook();
|
||||
const [isReady, cancel] = hook.result.current;
|
||||
|
||||
expect(spy).toHaveBeenCalledTimes(1);
|
||||
expect(isReady()).toBe(false);
|
||||
|
||||
act(() => {
|
||||
cancel();
|
||||
});
|
||||
jest.advanceTimersByTime(5);
|
||||
|
||||
expect(spy).toHaveBeenCalledTimes(1);
|
||||
expect(isReady()).toBe(null);
|
||||
});
|
||||
|
||||
it('third function should reset timeout', done => {
|
||||
const [spy, hook] = getHook();
|
||||
const [isReady, cancel, reset] = hook.result.current;
|
||||
|
||||
expect(isReady()).toBe(false);
|
||||
|
||||
act(() => {
|
||||
cancel();
|
||||
});
|
||||
jest.advanceTimersByTime(5);
|
||||
|
||||
expect(isReady()).toBe(null);
|
||||
|
||||
act(() => {
|
||||
reset();
|
||||
});
|
||||
expect(isReady()).toBe(false);
|
||||
|
||||
hook.waitForNextUpdate().then(() => {
|
||||
expect(spy).toHaveBeenCalledTimes(2);
|
||||
expect(isReady()).toBe(true);
|
||||
|
||||
done();
|
||||
});
|
||||
jest.advanceTimersByTime(5);
|
||||
});
|
||||
|
||||
it('should reset timeout on delay change', done => {
|
||||
const [spy, hook] = getHook(15);
|
||||
|
||||
expect(spy).toHaveBeenCalledTimes(1);
|
||||
hook.rerender({ delay: 5 });
|
||||
|
||||
hook.waitForNextUpdate().then(() => {
|
||||
expect(spy).toHaveBeenCalledTimes(3);
|
||||
|
||||
done();
|
||||
});
|
||||
jest.advanceTimersByTime(15);
|
||||
});
|
||||
});
|
||||
|
||||
116
src/__tests__/useTimeoutFn.test.ts
Normal file
116
src/__tests__/useTimeoutFn.test.ts
Normal file
@ -0,0 +1,116 @@
|
||||
import { act, renderHook, RenderHookResult } from '@testing-library/react-hooks';
|
||||
import { useTimeoutFn } from '../index';
|
||||
import { UseTimeoutFnReturn } from '../useTimeoutFn';
|
||||
|
||||
describe('useTimeoutFn', () => {
|
||||
beforeAll(() => {
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllTimers();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(useTimeoutFn).toBeDefined();
|
||||
});
|
||||
|
||||
it('should return three functions', () => {
|
||||
const hook = renderHook(() => useTimeoutFn(() => {}, 5));
|
||||
|
||||
expect(hook.result.current.length).toBe(3);
|
||||
expect(typeof hook.result.current[0]).toBe('function');
|
||||
expect(typeof hook.result.current[1]).toBe('function');
|
||||
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 } })];
|
||||
}
|
||||
|
||||
it('should call passed function after given amount of time', () => {
|
||||
const [spy] = getHook();
|
||||
|
||||
expect(spy).not.toHaveBeenCalled();
|
||||
jest.advanceTimersByTime(5);
|
||||
expect(spy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should cancel function call on unmount', () => {
|
||||
const [spy, hook] = getHook();
|
||||
|
||||
expect(spy).not.toHaveBeenCalled();
|
||||
hook.unmount();
|
||||
jest.advanceTimersByTime(5);
|
||||
expect(spy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('first function should return actual state of timeout', () => {
|
||||
let [, hook] = getHook();
|
||||
let [isReady] = hook.result.current;
|
||||
|
||||
expect(isReady()).toBe(false);
|
||||
hook.unmount();
|
||||
expect(isReady()).toBe(null);
|
||||
|
||||
[, hook] = getHook();
|
||||
[isReady] = hook.result.current;
|
||||
jest.advanceTimersByTime(5);
|
||||
expect(isReady()).toBe(true);
|
||||
});
|
||||
|
||||
it('second function should cancel timeout', () => {
|
||||
const [spy, hook] = getHook();
|
||||
const [isReady, cancel] = hook.result.current;
|
||||
|
||||
expect(spy).not.toHaveBeenCalled();
|
||||
expect(isReady()).toBe(false);
|
||||
|
||||
act(() => {
|
||||
cancel();
|
||||
});
|
||||
jest.advanceTimersByTime(5);
|
||||
|
||||
expect(spy).not.toHaveBeenCalled();
|
||||
expect(isReady()).toBe(null);
|
||||
});
|
||||
|
||||
it('third function should reset timeout', () => {
|
||||
const [spy, hook] = getHook();
|
||||
const [isReady, cancel, reset] = hook.result.current;
|
||||
|
||||
expect(isReady()).toBe(false);
|
||||
|
||||
act(() => {
|
||||
cancel();
|
||||
});
|
||||
jest.advanceTimersByTime(5);
|
||||
|
||||
expect(isReady()).toBe(null);
|
||||
|
||||
act(() => {
|
||||
reset();
|
||||
});
|
||||
expect(isReady()).toBe(false);
|
||||
|
||||
jest.advanceTimersByTime(5);
|
||||
|
||||
expect(spy).toHaveBeenCalledTimes(1);
|
||||
expect(isReady()).toBe(true);
|
||||
});
|
||||
|
||||
it('should reset timeout on delay change', () => {
|
||||
const [spy, hook] = getHook(50);
|
||||
|
||||
expect(spy).not.toHaveBeenCalled();
|
||||
hook.rerender({ delay: 5 });
|
||||
|
||||
jest.advanceTimersByTime(5);
|
||||
expect(spy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
@ -73,6 +73,7 @@ export { default as useStartTyping } from './useStartTyping';
|
||||
export { default as useThrottle } from './useThrottle';
|
||||
export { default as useThrottleFn } from './useThrottleFn';
|
||||
export { default as useTimeout } from './useTimeout';
|
||||
export { default as useTimeoutFn } from './useTimeoutFn';
|
||||
export { default as useTitle } from './useTitle';
|
||||
export { default as useToggle } from './useToggle';
|
||||
export { default as useTween } from './useTween';
|
||||
|
||||
@ -1,19 +1,10 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import useTimeoutFn from './useTimeoutFn';
|
||||
import useUpdate from './useUpdate';
|
||||
|
||||
const useTimeout = (ms: number = 0) => {
|
||||
const [ready, setReady] = useState(false);
|
||||
export type UseTimeoutReturn = [() => boolean | null, () => void, () => void];
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
setReady(true);
|
||||
}, ms);
|
||||
export default function useTimeout(ms: number = 0): UseTimeoutReturn {
|
||||
const update = useUpdate();
|
||||
|
||||
return () => {
|
||||
clearTimeout(timer);
|
||||
};
|
||||
}, [ms]);
|
||||
|
||||
return ready;
|
||||
};
|
||||
|
||||
export default useTimeout;
|
||||
return useTimeoutFn(update, ms);
|
||||
}
|
||||
|
||||
29
src/useTimeoutFn.ts
Normal file
29
src/useTimeoutFn.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { useCallback, useEffect, useRef } from 'react';
|
||||
|
||||
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(0);
|
||||
|
||||
const isReady = useCallback(() => ready.current, []);
|
||||
const set = useCallback(() => {
|
||||
ready.current = false;
|
||||
timeout.current = window.setTimeout(() => {
|
||||
ready.current = true;
|
||||
fn();
|
||||
}, ms);
|
||||
}, [ms, fn]);
|
||||
const clear = useCallback(() => {
|
||||
ready.current = null;
|
||||
timeout.current && clearTimeout(timeout.current);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
set();
|
||||
|
||||
return clear;
|
||||
}, [ms]);
|
||||
|
||||
return [isReady, clear, set];
|
||||
}
|
||||
29
yarn.lock
29
yarn.lock
@ -10948,10 +10948,10 @@ select@^1.1.2:
|
||||
resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d"
|
||||
integrity sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=
|
||||
|
||||
semantic-release@15.13.21:
|
||||
version "15.13.21"
|
||||
resolved "https://registry.yarnpkg.com/semantic-release/-/semantic-release-15.13.21.tgz#d021c75f889cff75ae3410736942bee6c4557da7"
|
||||
integrity sha512-3S9thQas28iv3NeHUqQVsDnxMcBGQICdxabeNnJ8BnbRBvCkgqCg3v9zo/+O5a8GCyxrgjtwJ2iWozL8SiIq1w==
|
||||
semantic-release@15.13.24:
|
||||
version "15.13.24"
|
||||
resolved "https://registry.yarnpkg.com/semantic-release/-/semantic-release-15.13.24.tgz#f0b9544427d059ba5e3c89ac1545234130796be7"
|
||||
integrity sha512-OPshm6HSp+KmZP9dUv1o3MRILDgOeHYWPI+XSpQRERMri7QkaEiIPkZzoNm2d6KDeFDnp03GphQQS4+Zfo+x/Q==
|
||||
dependencies:
|
||||
"@semantic-release/commit-analyzer" "^6.1.0"
|
||||
"@semantic-release/error" "^2.2.0"
|
||||
@ -10978,7 +10978,7 @@ semantic-release@15.13.21:
|
||||
resolve-from "^5.0.0"
|
||||
semver "^6.0.0"
|
||||
signale "^1.2.1"
|
||||
yargs "^13.1.0"
|
||||
yargs "^14.0.0"
|
||||
|
||||
semver-compare@^1.0.0:
|
||||
version "1.0.0"
|
||||
@ -12886,7 +12886,7 @@ yargs@^11.0.0:
|
||||
y18n "^3.2.1"
|
||||
yargs-parser "^9.0.2"
|
||||
|
||||
yargs@^13.1.0, yargs@^13.3.0:
|
||||
yargs@^13.3.0:
|
||||
version "13.3.0"
|
||||
resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.0.tgz#4c657a55e07e5f2cf947f8a366567c04a0dedc83"
|
||||
integrity sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==
|
||||
@ -12902,6 +12902,23 @@ yargs@^13.1.0, yargs@^13.3.0:
|
||||
y18n "^4.0.0"
|
||||
yargs-parser "^13.1.1"
|
||||
|
||||
yargs@^14.0.0:
|
||||
version "14.0.0"
|
||||
resolved "https://registry.yarnpkg.com/yargs/-/yargs-14.0.0.tgz#ba4cacc802b3c0b3e36a9e791723763d57a85066"
|
||||
integrity sha512-ssa5JuRjMeZEUjg7bEL99AwpitxU/zWGAGpdj0di41pOEmJti8NR6kyUIJBkR78DTYNPZOU08luUo0GTHuB+ow==
|
||||
dependencies:
|
||||
cliui "^5.0.0"
|
||||
decamelize "^1.2.0"
|
||||
find-up "^3.0.0"
|
||||
get-caller-file "^2.0.1"
|
||||
require-directory "^2.1.1"
|
||||
require-main-filename "^2.0.0"
|
||||
set-blocking "^2.0.0"
|
||||
string-width "^3.0.0"
|
||||
which-module "^2.0.0"
|
||||
y18n "^4.0.0"
|
||||
yargs-parser "^13.1.1"
|
||||
|
||||
yn@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/yn/-/yn-3.0.0.tgz#0073c6b56e92aed652fbdfd62431f2d6b9a7a091"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user