feat: add useThrottle hook

This commit is contained in:
Va Da 2019-03-26 11:49:13 +01:00 committed by GitHub
commit 756bc992d4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 127 additions and 2 deletions

View File

@ -71,12 +71,13 @@
- [**Side-effects**](./docs/Side-effects.md)
- [`useAsync`](./docs/useAsync.md) — resolves an `async` function.
- [`useAsyncRetry`](./docs/useAsyncRetry.md) — `useAsync` with `retry()` method.
- [`useDebounce`](./docs/useDebounce.md) — debounces a function. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/side-effects-usedebounce--demo)
- [`useFavicon`](./docs/useFavicon.md) — sets favicon of the page.
- [`useLocalStorage`](./docs/useLocalStorage.md) — manages a value in `localStorage`.
- [`useLockBodyScroll`](./docs/useLockBodyScroll.md) — lock scrolling of the body element.
- [`useSessionStorage`](./docs/useSessionStorage.md) — manages a value in `sessionStorage`.
- [`useThrottle`](./docs/useThrottle.md) — throttles a function. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/side-effects-usethrottle--demo)
- [`useTitle`](./docs/useTitle.md) — sets title of the page.
- [`useDebounce`](./docs/useDebounce.md) — debounces a function.
<br/>
<br/>
- [**Lifecycles**](./docs/Lifecycles.md)

View File

@ -13,10 +13,12 @@ import { useDebounce } from 'react-use';
const Demo = () => {
const [state, setState] = React.useState('Typing stopped');
const [val, setVal] = React.useState('');
const [debouncedValue, setDebouncedValue] = React.useState('');
useDebounce(
() => {
setState('Typing stopped');
setDebouncedValue(val);
},
2000,
[val]
@ -34,6 +36,7 @@ const Demo = () => {
}}
/>
<div>{state}</div>
<div>Debounced value: {debouncedValue}</div>
</div>
);
};
@ -42,5 +45,5 @@ const Demo = () => {
## Reference
```ts
useDebouce(fn, ms: number, args: any[]);
useDebounce(fn, ms: number, args: any[]);
```

49
docs/useThrottle.md Normal file
View File

@ -0,0 +1,49 @@
# `useThrottle`
React hook that invokes a function and then delays subsequent function calls until after wait milliseconds have elapsed since the last time the throttled function was invoked.
The third argument is the array of values that the throttle depends on, in the same manner as useEffect. The throttle timeout will start when one of the values changes.
## Usage
```jsx
import React, { useState } from 'react';
import { useThrottle } from 'react-use';
const Demo = () => {
const [status, setStatus] = React.useState('Updating stopped');
const [value, setValue] = React.useState('');
const [throttledValue, setThrottledValue] = React.useState('');
useThrottle(
() => {
setStatus('Waiting for input...');
setThrottledValue(value);
},
2000,
[value]
);
return (
<div>
<input
type="text"
value={value}
placeholder="Throttled input"
onChange={({ currentTarget }) => {
setStatus('Updating stopped');
setValue(currentTarget.value);
}}
/>
<div>{status}</div>
<div>Throttled value: {throttledValue}</div>
</div>
);
};
```
## Reference
```ts
useThrottle(fn, ms: number, args: any[]);
```

View File

@ -6,10 +6,12 @@ import ShowDocs from '../util/ShowDocs';
const Demo = () => {
const [state, setState] = React.useState('Typing stopped');
const [val, setVal] = React.useState('');
const [debouncedValue, setDebouncedValue] = React.useState('');
useDebounce(
() => {
setState('Typing stopped');
setDebouncedValue(val);
},
2000,
[val]
@ -27,6 +29,7 @@ const Demo = () => {
}}
/>
<div>{state}</div>
<div>Debounced value: {debouncedValue}</div>
</div>
);
};

View File

@ -0,0 +1,39 @@
import * as React from 'react';
import { storiesOf } from '@storybook/react';
import { useThrottle } from '..';
import ShowDocs from '../util/ShowDocs';
const Demo = () => {
const [status, setStatus] = React.useState('Updating stopped');
const [value, setValue] = React.useState('');
const [throttledValue, setThrottledValue] = React.useState('');
useThrottle(
() => {
setStatus('Waiting for input...');
setThrottledValue(value);
},
2000,
[value]
);
return (
<div>
<input
type="text"
value={value}
placeholder="Throttled input"
onChange={({ currentTarget }) => {
setStatus('Updating stopped');
setValue(currentTarget.value);
}}
/>
<div>{status}</div>
<div>Throttled value: {throttledValue}</div>
</div>
);
};
storiesOf('Side effects|useThrottle', module)
.add('Docs', () => <ShowDocs md={require('../../docs/useThrottle.md')} />)
.add('Demo', () => <Demo />);

View File

@ -43,6 +43,7 @@ import useSetState from './useSetState';
import useSize from './useSize';
import useSpeech from './useSpeech';
import useSpring from './useSpring';
import useThrottle from './useThrottle';
import useTimeout from './useTimeout';
import useTitle from './useTitle';
import useToggle from './useToggle';
@ -101,6 +102,7 @@ export {
useSize,
useSpeech,
useSpring,
useThrottle,
useTimeout,
useTitle,
useToggle,

28
src/useThrottle.ts Normal file
View File

@ -0,0 +1,28 @@
import { useRef, useEffect } from 'react';
const useThrottle = (fn: () => any, ms: number = 0, args?) => {
const lastRan = useRef(0);
useEffect(() => {
let timeout
const diff = Date.now() - lastRan.current
if (diff >= ms) {
fn.apply(null, args);
lastRan.current = Date.now();
} else {
timeout = setTimeout(() => {
fn.apply(null, args);
lastRan.current = Date.now();
}, ms - diff)
}
return () => {
if (timeout) {
clearTimeout(timeout);
}
}
}, args);
};
export default useThrottle;