Installations
npm install use-debounce
Score
96
Supply Chain
98
Quality
83.5
Maintenance
100
Vulnerability
100
License
Developer
xnimorz
Developer Guide
Module System
CommonJS, ESM
Min. Node Version
>= 16.0.0
Typescript Support
Yes
Node Version
22.8.0
NPM Version
10.8.2
Statistics
3,019 Stars
327 Commits
113 Forks
8 Watching
11 Branches
31 Contributors
Updated on 28 Nov 2024
Bundle Size
2.44 kB
Minified
1.00 kB
Minified + Gzipped
Languages
TypeScript (99.6%)
JavaScript (0.4%)
Total Downloads
Cumulative downloads
Total Downloads
194,408,396
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
Daily Downloads
Weekly Downloads
Monthly Downloads
Yearly Downloads
Peer Dependencies
1
Dev Dependencies
28
useDebounce, useDebouncedCallback & useThrottledCallback
React libraries for debouncing without tears!
- Small size < 1 Kb
- Compatible with underscore / lodash impl — learn once, use everywhere
- Server-rendering friendly!
Features
Install
1yarn add use-debounce 2# or 3npm i use-debounce --save
Copy paste guidance:
use-debounce
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
use-debounce callback
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
Changelog
https://github.com/xnimorz/use-debounce/blob/master/CHANGELOG.md
Simple values debouncing
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:
Debounced callbacks
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}
Returned value from 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});
Advanced usage
Cancel, maxWait and memoization
- Both
useDebounce
anduseDebouncedCallback
works withmaxWait
option. This params describes the maximum time func is allowed to be delayed before it's invoked. - You can cancel debounce cycle, by calling
cancel
callback
The 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
Flush method
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
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}
leading/trailing calls
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}
Options:
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 |
useThrottledCallback
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.
Special thanks:
@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
- Info: project has a license file: LICENSE:0
- Info: FSF or OSI recognized license: MIT License: LICENSE:0
Reason
2 existing vulnerabilities detected
Details
- Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275
- Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv
Reason
Found 2/11 approved changesets -- score normalized to 1
Reason
detected GitHub workflow tokens with excessive permissions
Details
- Warn: no topLevel permission defined: .github/workflows/main.yml:1
- Info: no jobLevel write permissions found
Reason
dependency not pinned by hash detected -- score normalized to 0
Details
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/xnimorz/use-debounce/main.yml/master?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/xnimorz/use-debounce/main.yml/master?enable=pin
- Warn: npmCommand not pinned by hash: .github/workflows/main.yml:23
- Info: 0 out of 2 GitHub-owned GitHubAction dependencies pinned
- Info: 0 out of 1 npmCommand dependencies pinned
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
- Warn: no security policy file detected
- Warn: no security file to analyze
- Warn: no security file to analyze
- Warn: no security file to analyze
Reason
project is not fuzzed
Details
- Warn: no fuzzer integrations found
Reason
branch protection not enabled on development/release branches
Details
- Warn: branch protection not enabled for branch 'master'
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
- Warn: 0 commits out of 24 are checked with a SAST tool
Score
4.3
/10
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