Gathering detailed insights and metrics for use-debounce
Gathering detailed insights and metrics for use-debounce
Gathering detailed insights and metrics for use-debounce
Gathering detailed insights and metrics for use-debounce
npm install use-debounce
96
Supply Chain
98
Quality
83.5
Maintenance
100
Vulnerability
100
License
Module System
Min. Node Version
Typescript Support
Node Version
NPM Version
3,019 Stars
327 Commits
113 Forks
8 Watching
11 Branches
31 Contributors
Updated on 28 Nov 2024
Minified
Minified + Gzipped
TypeScript (99.6%)
JavaScript (0.4%)
Cumulative downloads
Total Downloads
Last day
-4%
275,707
Compared to previous day
Last week
5.7%
1,542,987
Compared to previous week
Last month
10.2%
6,650,542
Compared to previous month
Last year
20.8%
66,024,060
Compared to previous year
1
28
React libraries for debouncing without tears!
1yarn add use-debounce 2# or 3npm i use-debounce --save
Simple usage: https://codesandbox.io/s/kx75xzyrq7
Debounce HTTP request: https://codesandbox.io/s/rr40wnropq
Debounce HTTP request with leading
param: https://codesandbox.io/s/cache-example-with-areas-and-leading-param-119r3i
Simple usage: https://codesandbox.io/s/x0jvqrwyq
Combining with native event listeners: https://codesandbox.io/s/32yqlyo815
Cancelling, maxWait and memoization: https://codesandbox.io/s/4wvmp1xlw4
HTTP requests: https://codesandbox.io/s/use-debounce-callback-http-y1h3m6
https://github.com/xnimorz/use-debounce/blob/master/CHANGELOG.md
According to https://twitter.com/dan_abramov/status/1060729512227467264 WebArchive link: https://web.archive.org/web/20210828073432/https://twitter.com/dan_abramov/status/1060729512227467264
1import React, { useState } from 'react'; 2import { useDebounce } from 'use-debounce'; 3 4export default function Input() { 5 const [text, setText] = useState('Hello'); 6 const [value] = useDebounce(text, 1000); 7 8 return ( 9 <div> 10 <input 11 defaultValue={'Hello'} 12 onChange={(e) => { 13 setText(e.target.value); 14 }} 15 /> 16 <p>Actual value: {text}</p> 17 <p>Debounce value: {value}</p> 18 </div> 19 ); 20}
This hook compares prev and next value using shallow equal. It means, setting an object {}
will trigger debounce timer. If you have to compare objects (https://github.com/xnimorz/use-debounce/issues/27#issuecomment-496828063), you can use useDebouncedCallback
, that is explained below:
Besides useDebounce
for values you can debounce callbacks, that is the more commonly understood kind of debouncing.
Example with Input (and react callbacks): https://codesandbox.io/s/x0jvqrwyq
1import { useDebouncedCallback } from 'use-debounce'; 2 3function Input({ defaultValue }) { 4 const [value, setValue] = useState(defaultValue); 5 // Debounce callback 6 const debounced = useDebouncedCallback( 7 // function 8 (value) => { 9 setValue(value); 10 }, 11 // delay in ms 12 1000 13 ); 14 15 // you should use `e => debounced(e.target.value)` as react works with synthetic events 16 return ( 17 <div> 18 <input 19 defaultValue={defaultValue} 20 onChange={(e) => debounced(e.target.value)} 21 /> 22 <p>Debounced value: {value}</p> 23 </div> 24 ); 25}
Example with Scroll (and native event listeners): https://codesandbox.io/s/32yqlyo815
1function ScrolledComponent() { 2 // just a counter to show, that there are no any unnessesary updates 3 const updatedCount = useRef(0); 4 updatedCount.current++; 5 6 const [position, setPosition] = useState(window.pageYOffset); 7 8 // Debounce callback 9 const debounced = useDebouncedCallback( 10 // function 11 () => { 12 setPosition(window.pageYOffset); 13 }, 14 // delay in ms 15 800 16 ); 17 18 useEffect(() => { 19 const unsubscribe = subscribe(window, 'scroll', debounced); 20 return () => { 21 unsubscribe(); 22 }; 23 }, []); 24 25 return ( 26 <div style={{ height: 10000 }}> 27 <div style={{ position: 'fixed', top: 0, left: 0 }}> 28 <p>Debounced top position: {position}</p> 29 <p>Component rerendered {updatedCount.current} times</p> 30 </div> 31 </div> 32 ); 33}
debounced()
Subsequent calls to the debounced function debounced
return the result of the last func invocation.
Note, that if there are no previous invocations it's mean you will get undefined. You should check it in your code properly.
Example:
1it('Subsequent calls to the debounced function `debounced` return the result of the last func invocation.', () => { 2 const callback = jest.fn(() => 42); 3 4 let callbackCache; 5 function Component() { 6 const debounced = useDebouncedCallback(callback, 1000); 7 callbackCache = debounced; 8 return null; 9 } 10 Enzyme.mount(<Component />); 11 12 const result = callbackCache(); 13 expect(callback.mock.calls.length).toBe(0); 14 expect(result).toBeUndefined(); 15 16 act(() => { 17 jest.runAllTimers(); 18 }); 19 expect(callback.mock.calls.length).toBe(1); 20 const subsequentResult = callbackCache(); 21 22 expect(callback.mock.calls.length).toBe(1); 23 expect(subsequentResult).toBe(42); 24});
useDebounce
and useDebouncedCallback
works with maxWait
option. This params describes the maximum time func is allowed to be delayed before it's invoked.cancel
callbackThe full example you can see here https://codesandbox.io/s/4wvmp1xlw4
1import React, { useState } from 'react'; 2import ReactDOM from 'react-dom'; 3import { useDebouncedCallback } from 'use-debounce'; 4 5function Input({ defaultValue }) { 6 const [value, setValue] = useState(defaultValue); 7 const debounced = useDebouncedCallback( 8 (value) => { 9 setValue(value); 10 }, 11 500, 12 // The maximum time func is allowed to be delayed before it's invoked: 13 { maxWait: 2000 } 14 ); 15 16 // you should use `e => debounced(e.target.value)` as react works with synthetic events 17 return ( 18 <div> 19 <input 20 defaultValue={defaultValue} 21 onChange={(e) => debounced(e.target.value)} 22 /> 23 <p>Debounced value: {value}</p> 24 <button onClick={debounced.cancel}>Cancel Debounce cycle</button> 25 </div> 26 ); 27} 28 29const rootElement = document.getElementById('root'); 30ReactDOM.render(<Input defaultValue="Hello world" />, rootElement);
The same API is available for useDebounce
calls:
1const [value, {cancel, isPending, flush}] = useDebounce(valueToDebounce); 2... 3cancel() // cancels pending debounce request 4isPending() // returns if there is a pending debouncing request 5flush() // immediately flushes pending request
useDebouncedCallback
has flush
method. It allows to call the callback manually if it hasn't fired yet. This method is handy to use when the user takes an action that would cause the component to unmount, but you need to execute the callback.
1import React, { useState } from 'react'; 2import { useDebouncedCallback } from 'use-debounce'; 3 4function InputWhichFetchesSomeData({ defaultValue, asyncFetchData }) { 5 const debounced = useDebouncedCallback( 6 (value) => { 7 asyncFetchData; 8 }, 9 500, 10 { maxWait: 2000 } 11 ); 12 13 // When the component goes to be unmounted, we will fetch data if the input has changed. 14 useEffect( 15 () => () => { 16 debounced.flush(); 17 }, 18 [debounced] 19 ); 20 21 return ( 22 <input 23 defaultValue={defaultValue} 24 onChange={(e) => debounced(e.target.value)} 25 /> 26 ); 27}
isPending
method shows whether component has pending callbacks. Works for both useDebounce
and useDebouncedCallback
:
1import React, { useCallback } from 'react'; 2 3function Component({ text }) { 4 const debounced = useDebouncedCallback( 5 useCallback(() => {}, []), 6 500 7 ); 8 9 expect(debounced.isPending()).toBeFalsy(); 10 debounced(); 11 expect(debounced.isPending()).toBeTruthy(); 12 debounced.flush(); 13 expect(debounced.isPending()).toBeFalsy(); 14 15 return <span>{text}</span>; 16}
Both useDebounce
and useDebouncedCallback
work with the leading
and trailing
options. leading
param will execute the function once immediately when called. Subsequent calls will be debounced until the timeout expires. trailing
option controls whenever to call the callback after timeout again.
For more information on how leading debounce calls work see: https://lodash.com/docs/#debounce
1import React, { useState } from 'react'; 2import { useDebounce } from 'use-debounce'; 3 4export default function Input() { 5 const [text, setText] = useState('Hello'); 6 const [value] = useDebounce(text, 1000, { leading: true }); 7 8 // value is updated immediately when text changes the first time, 9 // but all subsequent changes are debounced. 10 return ( 11 <div> 12 <input 13 defaultValue={'Hello'} 14 onChange={(e) => { 15 setText(e.target.value); 16 }} 17 /> 18 <p>Actual value: {text}</p> 19 <p>Debounce value: {value}</p> 20 </div> 21 ); 22}
You can provide additional options as a third argument to both useDebounce
and useDebouncedCallback
:
option | default | Description | Example |
---|---|---|---|
maxWait | - | Describes the maximum time func is allowed to be delayed before it's invoked | https://github.com/xnimorz/use-debounce#cancel-maxwait-and-memoization |
leading | - | This param will execute the function once immediately when called. Subsequent calls will be debounced until the timeout expires. | https://github.com/xnimorz/use-debounce#leading-calls |
trailing | true | This param executes the function after timeout. | https://github.com/xnimorz/use-debounce#leading-calls |
equalityFn | (prev, next) => prev === next | [useDebounce ONLY] Comparator function which shows if timeout should be started |
You are able to use throttled callback with this library also (starting 5.2.0 version). For this purpose use:
import useThrottledCallback from 'use-debounce/useThrottledCallback';
or
import { useThrottledCallback } from 'use-debounce';
Several examples:
Avoid excessively updating the position while scrolling.
1const scrollHandler = useThrottledCallback(updatePosition, 100);
2window.addEventListener('scroll', scrollHandler);
Invoke renewToken
when the click event is fired, but not more than once every 5 minutes.
1const throttled = useThrottledCallback(renewToken, 300000, { 'trailing': false }) 2<button onClick={throttled}>click</button>
All the params for useThrottledCallback
are the same as for useDebouncedCallback
except maxWait
option. As it's not needed for throttle callbacks.
@tryggvigy — for managing lots of new features of the library like trailing and leading params, throttle callback, etc;
@omgovich — for reducing bundle size.
No vulnerabilities found.
Reason
no dangerous workflow patterns detected
Reason
5 commit(s) and 8 issue activity found in the last 90 days -- score normalized to 10
Reason
no binaries found in the repo
Reason
license file detected
Details
Reason
2 existing vulnerabilities detected
Details
Reason
Found 2/11 approved changesets -- score normalized to 1
Reason
detected GitHub workflow tokens with excessive permissions
Details
Reason
dependency not pinned by hash detected -- score normalized to 0
Details
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
Reason
project is not fuzzed
Details
Reason
branch protection not enabled on development/release branches
Details
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
Score
Last Scanned on 2024-11-18
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More