Skip to content

Commit

Permalink
feat: 🎸 add useThrottleFn hook that throttles function
Browse files Browse the repository at this point in the history
This hook used to be called useThrottle, but it also was re-implemented.
  • Loading branch information
streamich committed Mar 27, 2019
1 parent 452e8d9 commit 0ccdf95
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 4 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
- [`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)
- [`useThrottle` and `useThrottleFn`](./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.
<br/>
<br/>
Expand Down
8 changes: 5 additions & 3 deletions docs/useThrottle.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
# `useThrottle`
# `useThrottle` and `useThrottleFn`

React hook that throttles a value.
React hooks that throttle.

## Usage

```jsx
import React, { useState } from 'react';
import { useThrottle } from 'react-use';
import { useThrottle, useThrottleFn } from 'react-use';

const Demo = ({value}) => {
const throttledValue = useThrottle(value);
// const throttledValue = useThrottleFn(value => value, 200, [value]);

return (
<>
Expand All @@ -24,4 +25,5 @@ const Demo = ({value}) => {

```ts
useThrottle(value, ms?: number);
useThrottleFn(fn, ms, args);
```
40 changes: 40 additions & 0 deletions src/__stories__/useThrottleFn.story.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import * as React from 'react';
import { storiesOf } from '@storybook/react';
import { useThrottleFn, useCounter } from '..';
import ShowDocs from '../util/ShowDocs';

const Demo = () => {
const [value, setValue] = React.useState('');
const throttledValue = useThrottleFn(value => value, 2000, [value]);
const [lastThrottledValue, setLastThrottledValue] = React.useState(throttledValue);
const [count, {inc}] = useCounter();

React.useEffect(() => {
if (lastThrottledValue !== throttledValue) {
setLastThrottledValue(throttledValue);
inc();
}
});

return (
<div style={{width: 300, margin: '40px auto'}}>
<input
type="text"
value={value}
placeholder="Throttled input"
style={{width: '100%'}}
onChange={({ currentTarget }) => {
setValue(currentTarget.value);
}}
/>
<br />
<br />
<div>Throttled value: {throttledValue}</div>
<div>Times updated: {count}</div>
</div>
);
};

storiesOf('Side effects|useThrottleFn', module)
.add('Docs', () => <ShowDocs md={require('../../docs/useThrottle.md')} />)
.add('Demo', () => <Demo />);
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import useSize from './useSize';
import useSpeech from './useSpeech';
import useSpring from './useSpring';
import useThrottle from './useThrottle';
import useThrottleFn from './useThrottleFn';
import useTimeout from './useTimeout';
import useTitle from './useTitle';
import useToggle from './useToggle';
Expand Down Expand Up @@ -107,6 +108,7 @@ export {
useSpeech,
useSpring,
useThrottle,
useThrottleFn,
useTimeout,
useTitle,
useToggle,
Expand Down
36 changes: 36 additions & 0 deletions src/useThrottleFn.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import {useState, useRef, useEffect} from 'react';
import useUnmount from './useUnmount'

const useThrottleFn = <T>(fn: (...args: any[]) => T, ms: number = 200, args: any[]) => {
const [state, setState] = useState<T>(null as any);
let timeout = useRef<any>(null);
const nextArgs = useRef(null) as any;
const hasNextArgs = useRef(false) as any;

useEffect(() => {
if (!timeout.current) {
setState(fn(...args));
const timeoutCallback = () => {
if (hasNextArgs.current) {
hasNextArgs.current = false;
setState(fn(...nextArgs.current));
timeout.current = setTimeout(timeoutCallback, ms);
} else {
timeout.current = null;
}
};
timeout.current = setTimeout(timeoutCallback, ms);
} else {
nextArgs.current = args;
hasNextArgs.current = true;
}
}, args);

useUnmount(() => {
clearTimeout(timeout.current);
});

return state;
};

export default useThrottleFn;

0 comments on commit 0ccdf95

Please sign in to comment.