Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

use-debounce

Package Overview
Dependencies
Maintainers
1
Versions
80
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

use-debounce - npm Package Compare versions

Comparing version 5.0.1 to 5.0.2

35

CHANGELOG.md

@@ -0,1 +1,36 @@

## 5.0.2
- Add size-limit and configure it for esm modules. Now the size of the whole library is limited within 1 KB (thanks to [@omgovich](https://github.com/omgovich))
- Add an [export map](https://docs.skypack.dev/package-authors/package-checks#export-map) to your package.json. (thanks to [@omgovich](https://github.com/omgovich))
- Reduce bundle size (thanks to [@omgovich](https://github.com/omgovich)):
Before:
```
esm/index.js
Size: 908 B with all dependencies, minified and gzipped
esm/index.js
Size: 873 B with all dependencies, minified and gzipped
esm/index.js
Size: 755 B with all dependencies, minified and gzipped
```
Now:
```
esm/index.js
Size: 826 B with all dependencies, minified and gzipped
esm/index.js
Size: 790 B with all dependencies, minified and gzipped
esm/index.js
Size: 675 B with all dependencies, minified and gzipped
```
- Add notes about returned value from `debounced.callback` and its subsequent calls: https://github.com/xnimorz/use-debounce#returned-value-from-debouncedcallback
- Add project logo (thanks to [@omgovich](https://github.com/omgovich)):
<img src="logo.png" width="500" alt="use-debounce" />
## 5.0.1

@@ -2,0 +37,0 @@

2

esm/useDebounce.js

@@ -7,3 +7,3 @@ import { useCallback, useEffect, useRef, useState } from 'react';

export default function useDebounce(value, delay, options) {
var eq = options && options.equalityFn ? options.equalityFn : valueEquality;
var eq = (options && options.equalityFn) || valueEquality;
var _a = useState(value), state = _a[0], dispatch = _a[1];

@@ -10,0 +10,0 @@ var debounced = useDebouncedCallback(useCallback(function (value) { return dispatch(value); }, []), delay, options);

@@ -11,2 +11,6 @@ export interface Options {

}
/**
* Subsequent calls to the debounced function `debounced.callback` 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.
*/
export interface DebouncedState<T extends (...args: any[]) => ReturnType<T>> extends ControlFunctions {

@@ -13,0 +17,0 @@ callback: (...args: Parameters<T>) => ReturnType<T>;

import { useRef, useCallback, useEffect, useMemo } from 'react';
export default function useDebouncedCallback(func, wait, options) {
var _this = this;
if (options === void 0) { options = { leading: false, trailing: true }; }
var lastCallTime = useRef(undefined);
var lastCallTime = useRef(null);
var lastInvokeTime = useRef(0);
var timerId = useRef(undefined);
var timerId = useRef(null);
var lastArgs = useRef([]);
var lastThis = useRef(null);
var result = useRef(null);
var lastThis = useRef();
var result = useRef();
var funcRef = useRef(func);

@@ -15,38 +14,24 @@ var mounted = useRef(true);

// Bypass `requestAnimationFrame` by explicitly setting `wait=0`.
var useRAF = !wait && wait !== 0 && typeof window !== 'undefined' && typeof window.requestAnimationFrame === 'function';
var useRAF = !wait && wait !== 0 && typeof window !== 'undefined';
if (typeof func !== 'function') {
throw new TypeError('Expected a function');
}
wait = Number(wait) || 0;
wait = +wait || 0;
options = options || {};
var leading = !!options.leading;
var trailing = 'trailing' in options ? !!options.trailing : true;
var trailing = 'trailing' in options ? !!options.trailing : true; // `true` by default
var maxing = 'maxWait' in options;
var maxWait = maxing ? Math.max(Number(options.maxWait) || 0, wait) : undefined;
var maxWait = maxing ? Math.max(+options.maxWait || 0, wait) : null;
var invokeFunc = useCallback(function (time) {
var args = lastArgs.current;
var thisArg = lastThis.current;
lastArgs.current = lastThis.current = undefined;
lastArgs.current = lastThis.current = null;
lastInvokeTime.current = time;
result.current = funcRef.current.apply(thisArg, args);
return result.current;
return (result.current = funcRef.current.apply(thisArg, args));
}, []);
var startTimer = useCallback(function (pendingFunc, wait) {
if (useRAF) {
window.cancelAnimationFrame(timerId.current);
return window.requestAnimationFrame(pendingFunc);
}
return setTimeout(pendingFunc, wait);
if (useRAF)
cancelAnimationFrame(timerId.current);
timerId.current = useRAF ? requestAnimationFrame(pendingFunc) : setTimeout(pendingFunc, wait);
}, [useRAF]);
var cancelTimer = useCallback(function (id) {
if (useRAF) {
return window.cancelAnimationFrame(id);
}
clearTimeout(id);
}, [useRAF]);
var remainingWait = useCallback(function (time) {
var timeSinceLastCall = time - lastCallTime.current;
var timeSinceLastInvoke = time - lastInvokeTime.current;
var timeWaiting = wait - timeSinceLastCall;
return maxing ? Math.min(timeWaiting, maxWait - timeSinceLastInvoke) : timeWaiting;
}, [maxWait, maxing, wait]);
var shouldInvoke = useCallback(function (time) {

@@ -60,3 +45,3 @@ if (!mounted.current)

// it as the trailing edge, or we've hit the `maxWait` limit.
return (lastCallTime.current === undefined ||
return (!lastCallTime.current ||
timeSinceLastCall >= wait ||

@@ -67,3 +52,3 @@ timeSinceLastCall < 0 ||

var trailingEdge = useCallback(function (time) {
timerId.current = undefined;
timerId.current = null;
// Only invoke if we have `lastArgs` which means `func` has been

@@ -74,3 +59,3 @@ // debounced at least once.

}
lastArgs.current = lastThis.current = undefined;
lastArgs.current = lastThis.current = null;
return result.current;

@@ -83,22 +68,19 @@ }, [invokeFunc, trailing]);

}
// Restart the timer.
timerId.current = startTimer(timerExpired, remainingWait(time));
}, [remainingWait, shouldInvoke, startTimer, trailingEdge]);
var leadingEdge = useCallback(function (time) {
// Reset any `maxWait` timer.
lastInvokeTime.current = time;
// Start the timer for the trailing edge.
timerId.current = startTimer(timerExpired, wait);
// Invoke the leading edge.
return leading ? invokeFunc(time) : result.current;
}, [invokeFunc, startTimer, leading, timerExpired, wait]);
// Remaining wait calculation
var timeSinceLastCall = time - lastCallTime.current;
var timeSinceLastInvoke = time - lastInvokeTime.current;
var timeWaiting = wait - timeSinceLastCall;
var remainingWait = maxing ? Math.min(timeWaiting, maxWait - timeSinceLastInvoke) : timeWaiting;
// Restart the timer
startTimer(timerExpired, remainingWait);
}, [maxWait, maxing, shouldInvoke, startTimer, trailingEdge, wait]);
var cancel = useCallback(function () {
if (timerId.current !== undefined) {
cancelTimer(timerId.current);
if (timerId.current) {
useRAF ? cancelAnimationFrame(timerId.current) : clearTimeout(timerId.current);
}
lastInvokeTime.current = 0;
lastArgs.current = lastCallTime.current = lastThis.current = timerId.current = undefined;
}, [cancelTimer]);
lastArgs.current = lastCallTime.current = lastThis.current = timerId.current = null;
}, [useRAF]);
var flush = useCallback(function () {
return timerId.current === undefined ? result.current : trailingEdge(Date.now());
return !timerId.current ? result.current : trailingEdge(Date.now());
}, [trailingEdge]);

@@ -122,18 +104,23 @@ useEffect(function () {

if (isInvoking) {
if (timerId.current === undefined && mounted.current) {
return leadingEdge(lastCallTime.current);
if (!timerId.current && mounted.current) {
// Reset any `maxWait` timer.
lastInvokeTime.current = lastCallTime.current;
// Start the timer for the trailing edge.
startTimer(timerExpired, wait);
// Invoke the leading edge.
return leading ? invokeFunc(lastCallTime.current) : result.current;
}
if (maxing) {
// Handle invocations in a tight loop.
timerId.current = startTimer(timerExpired, wait);
startTimer(timerExpired, wait);
return invokeFunc(lastCallTime.current);
}
}
if (timerId.current === undefined) {
timerId.current = startTimer(timerExpired, wait);
if (!timerId.current) {
startTimer(timerExpired, wait);
}
return result.current;
}, [invokeFunc, leadingEdge, maxing, shouldInvoke, startTimer, timerExpired, wait]);
}, [invokeFunc, leading, maxing, shouldInvoke, startTimer, timerExpired, wait]);
var pending = useCallback(function () {
return timerId.current !== undefined;
return !!timerId.current;
}, []);

@@ -140,0 +127,0 @@ var debouncedState = useMemo(function () { return ({

@@ -9,3 +9,3 @@ "use strict";

function useDebounce(value, delay, options) {
var eq = options && options.equalityFn ? options.equalityFn : valueEquality;
var eq = (options && options.equalityFn) || valueEquality;
var _a = react_1.useState(value), state = _a[0], dispatch = _a[1];

@@ -12,0 +12,0 @@ var debounced = useDebouncedCallback_1.default(react_1.useCallback(function (value) { return dispatch(value); }, []), delay, options);

@@ -11,2 +11,6 @@ export interface Options {

}
/**
* Subsequent calls to the debounced function `debounced.callback` 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.
*/
export interface DebouncedState<T extends (...args: any[]) => ReturnType<T>> extends ControlFunctions {

@@ -13,0 +17,0 @@ callback: (...args: Parameters<T>) => ReturnType<T>;

@@ -6,9 +6,8 @@ "use strict";

var _this = this;
if (options === void 0) { options = { leading: false, trailing: true }; }
var lastCallTime = react_1.useRef(undefined);
var lastCallTime = react_1.useRef(null);
var lastInvokeTime = react_1.useRef(0);
var timerId = react_1.useRef(undefined);
var timerId = react_1.useRef(null);
var lastArgs = react_1.useRef([]);
var lastThis = react_1.useRef(null);
var result = react_1.useRef(null);
var lastThis = react_1.useRef();
var result = react_1.useRef();
var funcRef = react_1.useRef(func);

@@ -18,38 +17,24 @@ var mounted = react_1.useRef(true);

// Bypass `requestAnimationFrame` by explicitly setting `wait=0`.
var useRAF = !wait && wait !== 0 && typeof window !== 'undefined' && typeof window.requestAnimationFrame === 'function';
var useRAF = !wait && wait !== 0 && typeof window !== 'undefined';
if (typeof func !== 'function') {
throw new TypeError('Expected a function');
}
wait = Number(wait) || 0;
wait = +wait || 0;
options = options || {};
var leading = !!options.leading;
var trailing = 'trailing' in options ? !!options.trailing : true;
var trailing = 'trailing' in options ? !!options.trailing : true; // `true` by default
var maxing = 'maxWait' in options;
var maxWait = maxing ? Math.max(Number(options.maxWait) || 0, wait) : undefined;
var maxWait = maxing ? Math.max(+options.maxWait || 0, wait) : null;
var invokeFunc = react_1.useCallback(function (time) {
var args = lastArgs.current;
var thisArg = lastThis.current;
lastArgs.current = lastThis.current = undefined;
lastArgs.current = lastThis.current = null;
lastInvokeTime.current = time;
result.current = funcRef.current.apply(thisArg, args);
return result.current;
return (result.current = funcRef.current.apply(thisArg, args));
}, []);
var startTimer = react_1.useCallback(function (pendingFunc, wait) {
if (useRAF) {
window.cancelAnimationFrame(timerId.current);
return window.requestAnimationFrame(pendingFunc);
}
return setTimeout(pendingFunc, wait);
if (useRAF)
cancelAnimationFrame(timerId.current);
timerId.current = useRAF ? requestAnimationFrame(pendingFunc) : setTimeout(pendingFunc, wait);
}, [useRAF]);
var cancelTimer = react_1.useCallback(function (id) {
if (useRAF) {
return window.cancelAnimationFrame(id);
}
clearTimeout(id);
}, [useRAF]);
var remainingWait = react_1.useCallback(function (time) {
var timeSinceLastCall = time - lastCallTime.current;
var timeSinceLastInvoke = time - lastInvokeTime.current;
var timeWaiting = wait - timeSinceLastCall;
return maxing ? Math.min(timeWaiting, maxWait - timeSinceLastInvoke) : timeWaiting;
}, [maxWait, maxing, wait]);
var shouldInvoke = react_1.useCallback(function (time) {

@@ -63,3 +48,3 @@ if (!mounted.current)

// it as the trailing edge, or we've hit the `maxWait` limit.
return (lastCallTime.current === undefined ||
return (!lastCallTime.current ||
timeSinceLastCall >= wait ||

@@ -70,3 +55,3 @@ timeSinceLastCall < 0 ||

var trailingEdge = react_1.useCallback(function (time) {
timerId.current = undefined;
timerId.current = null;
// Only invoke if we have `lastArgs` which means `func` has been

@@ -77,3 +62,3 @@ // debounced at least once.

}
lastArgs.current = lastThis.current = undefined;
lastArgs.current = lastThis.current = null;
return result.current;

@@ -86,22 +71,19 @@ }, [invokeFunc, trailing]);

}
// Restart the timer.
timerId.current = startTimer(timerExpired, remainingWait(time));
}, [remainingWait, shouldInvoke, startTimer, trailingEdge]);
var leadingEdge = react_1.useCallback(function (time) {
// Reset any `maxWait` timer.
lastInvokeTime.current = time;
// Start the timer for the trailing edge.
timerId.current = startTimer(timerExpired, wait);
// Invoke the leading edge.
return leading ? invokeFunc(time) : result.current;
}, [invokeFunc, startTimer, leading, timerExpired, wait]);
// Remaining wait calculation
var timeSinceLastCall = time - lastCallTime.current;
var timeSinceLastInvoke = time - lastInvokeTime.current;
var timeWaiting = wait - timeSinceLastCall;
var remainingWait = maxing ? Math.min(timeWaiting, maxWait - timeSinceLastInvoke) : timeWaiting;
// Restart the timer
startTimer(timerExpired, remainingWait);
}, [maxWait, maxing, shouldInvoke, startTimer, trailingEdge, wait]);
var cancel = react_1.useCallback(function () {
if (timerId.current !== undefined) {
cancelTimer(timerId.current);
if (timerId.current) {
useRAF ? cancelAnimationFrame(timerId.current) : clearTimeout(timerId.current);
}
lastInvokeTime.current = 0;
lastArgs.current = lastCallTime.current = lastThis.current = timerId.current = undefined;
}, [cancelTimer]);
lastArgs.current = lastCallTime.current = lastThis.current = timerId.current = null;
}, [useRAF]);
var flush = react_1.useCallback(function () {
return timerId.current === undefined ? result.current : trailingEdge(Date.now());
return !timerId.current ? result.current : trailingEdge(Date.now());
}, [trailingEdge]);

@@ -125,18 +107,23 @@ react_1.useEffect(function () {

if (isInvoking) {
if (timerId.current === undefined && mounted.current) {
return leadingEdge(lastCallTime.current);
if (!timerId.current && mounted.current) {
// Reset any `maxWait` timer.
lastInvokeTime.current = lastCallTime.current;
// Start the timer for the trailing edge.
startTimer(timerExpired, wait);
// Invoke the leading edge.
return leading ? invokeFunc(lastCallTime.current) : result.current;
}
if (maxing) {
// Handle invocations in a tight loop.
timerId.current = startTimer(timerExpired, wait);
startTimer(timerExpired, wait);
return invokeFunc(lastCallTime.current);
}
}
if (timerId.current === undefined) {
timerId.current = startTimer(timerExpired, wait);
if (!timerId.current) {
startTimer(timerExpired, wait);
}
return result.current;
}, [invokeFunc, leadingEdge, maxing, shouldInvoke, startTimer, timerExpired, wait]);
}, [invokeFunc, leading, maxing, shouldInvoke, startTimer, timerExpired, wait]);
var pending = react_1.useCallback(function () {
return timerId.current !== undefined;
return !!timerId.current;
}, []);

@@ -143,0 +130,0 @@ var debouncedState = react_1.useMemo(function () { return ({

{
"name": "use-debounce",
"version": "5.0.1",
"version": "5.0.2",
"description": "Debounce hook for react",

@@ -8,8 +8,16 @@ "main": "lib/index.js",

"types": "./lib",
"exports": {
".": {
"import": "./dist/index.module.js",
"require": "./dist/index.js"
}
},
"sideEffects": false,
"scripts": {
"test": "yarn jest",
"build": "yarn test && eslint \"src/**.ts\" && rm -rf ./lib/* ./esm/* && yarn build:cjs && yarn build:es",
"size": "yarn build && size-limit",
"test": "yarn jest && eslint \"src/**.ts\"",
"build": "rm -rf ./lib/* ./esm/* && yarn build:cjs && yarn build:es",
"build:cjs": "tsc",
"build:es": "tsc -m esNext --outDir esm"
"build:es": "tsc -m esNext --outDir esm",
"prepublishOnly": "npm run build"
},

@@ -42,2 +50,3 @@ "engines": {

"devDependencies": {
"@size-limit/preset-small-lib": "^4.6.2",
"@types/enzyme": "^3.9.3",

@@ -66,2 +75,3 @@ "@types/enzyme-adapter-react-16": "^1.0.5",

"react-dom": "16.8.3",
"size-limit": "^4.6.2",
"ts-jest": "^26.3.0",

@@ -72,3 +82,19 @@ "typescript": "^3.5.1"

"kind-of": "6.0.3"
}
},
"size-limit": [
{
"path": "esm/index.js",
"limit": "1 KB"
},
{
"path": "esm/index.js",
"import": "{ useDebounce }",
"limit": "1 KB"
},
{
"path": "esm/index.js",
"import": "{ useDebouncedCallback }",
"limit": "1 KB"
}
]
}

@@ -1,5 +0,24 @@

# useDebounce react hook
<div align="center">
<a href="https://www.npmjs.com/package/use-debounce">
<img src="logo.png" width="500" alt="use-debounce" />
</a>
</div>
It provides:
<div align="center">
<a href="https://www.npmjs.com/package/use-debounce">
<img alt="npm" src="https://img.shields.io/npm/v/use-debounce.svg?labelColor=49516F&color=8994BC" />
</a>
<a href="https://npmjs.org/package/use-debounce">
<img alt="downloads" src="https://badgen.net/npm/dm/use-debounce?labelColor=49516F&color=8994BC" />
</a>
<a href="https://bundlephobia.com/result?p=use-debounce">
<img alt="tree-shakeable" src="https://badgen.net/bundlephobia/tree-shaking/use-debounce?labelColor=49516F&color=8994BC" />
</a>
<a href="https://npmjs.org/package/use-debounce">
<img alt="types included" src="https://badgen.net/npm/types/use-debounce?labelColor=49516F&color=8994BC" />
</a>
</div>
## Features
- [classic debounced callback](#debounced-callbacks)

@@ -9,11 +28,7 @@ - [**value** debouncing](#simple-values-debouncing)

Install it with yarn:
## Install
```
```sh
yarn add use-debounce
```
Or with npm:
```
# or
npm i use-debounce --save

@@ -31,3 +46,3 @@ ```

https://github.com/xnimorz/use-debounce/blob/master/CHANGELOG.md
https://github.com/xnimorz/use-debounce/blob/master/CHANGELOG.md

@@ -83,3 +98,3 @@ ## Simple values debouncing

// you should use `e => debounced.callback(e.target.value)` as react works with synthetic evens
// you should use `e => debounced.callback(e.target.value)` as react works with synthetic events
return (

@@ -132,2 +147,36 @@ <div>

### Returned value from `debounced.callback`
Subsequent calls to the debounced function `debounced.callback` 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:
```javascript
it('Subsequent calls to the debounced function `debounced.callback` return the result of the last func invocation.', () => {
const callback = jest.fn(() => 42);
let callbackCache;
function Component() {
const debounced = useDebouncedCallback(callback, 1000);
callbackCache = debounced.callback;
return null;
}
Enzyme.mount(<Component />);
const result = callbackCache();
expect(callback.mock.calls.length).toBe(0);
expect(result).toBeUndefined();
act(() => {
jest.runAllTimers();
});
expect(callback.mock.calls.length).toBe(1);
const subsequentResult = callbackCache();
expect(callback.mock.calls.length).toBe(1);
expect(subsequentResult).toBe(42);
});
```
### Advanced usage

@@ -158,3 +207,3 @@

// you should use `e => debounced.callback(e.target.value)` as react works with synthetic evens
// you should use `e => debounced.callback(e.target.value)` as react works with synthetic events
return (

@@ -220,5 +269,5 @@ <div>

#### leading calls
#### leading/trailing calls
Both `useDebounce` and `useDebouncedCallback` work with the `leading` option. This param will execute the function once immediately when called. Subsequent calls will be debounced until the timeout expires.
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.

@@ -260,2 +309,3 @@ For more information on how leading debounce calls work see: https://lodash.com/docs/#debounce

| 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 | Comparator function which shows if timeout should be started | |
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc