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.2.1 to 6.0.0-beta

86

CHANGELOG.md

@@ -0,1 +1,66 @@

## 6.0.0
- _breakind change_: removed `callback` field, instead of this `useDebouncedCallback` and `useThrottledCallback` returns a callable function:
Old:
```js
const { callback, pending } = useDebouncedCallback(/*...*/);
// ...
debounced.callback();
```
New:
```js
const debounced = useDebouncedCallback(/*...*/);
// ...
debounced();
/**
* Also debounced has fields:
* {
* cancel: () => void
* flush: () => void
* isPending: () => boolean
* }
* So you can call debounced.cancel(), debounced.flush(), debounced.isPending()
*/
```
It makes easier to understand which cancel \ flush or isPending is called in case you have several debounced functions in your component
- _breaking change_: Now `useDebounce`, `useDebouncedCallback` and `useThrottledCallback` has `isPending` method instead of `pending`
Old:
```js
const { callback, pending } = useDebouncedCallback(/*...*/);
```
New:
```js
const { callback, isPending } = useDebouncedCallback(/*...*/);
/**
* {
* callback: (...args: any[]) => ReturnType<T>
* cancel: () => void
* flush: () => void
* isPending: () => boolean
* }
*/
```
- get rid of `useCallback` calls
- improve internal typing
- decrease the amount of functions to initialize each `useDebouncedCallback` call
- reduce library size:
Whole library: from 946 B to 899 B === 47 B
useDebounce: from 844 to 791 === 53 B
useDebouncedCallback: from 680 to 623 === 57 B
useThrottledCallback: from 736 to 680 === 56 B
## 5.2.1

@@ -30,21 +95,24 @@

Before:
```
esm/index.js
esm/index.js
Size: 908 B with all dependencies, minified and gzipped
esm/index.js
esm/index.js
Size: 873 B with all dependencies, minified and gzipped
esm/index.js
esm/index.js
Size: 755 B with all dependencies, minified and gzipped
```
Now:
```
esm/index.js
esm/index.js
Size: 826 B with all dependencies, minified and gzipped
esm/index.js
esm/index.js
Size: 790 B with all dependencies, minified and gzipped
esm/index.js
esm/index.js
Size: 675 B with all dependencies, minified and gzipped

@@ -56,3 +124,3 @@ ```

- Add project logo (thanks to [@omgovich](https://github.com/omgovich)):
<img src="logo.png" width="500" alt="use-debounce" />
<img src="logo.png" width="500" alt="use-debounce" />

@@ -59,0 +127,0 @@ ## 5.0.1

4

esm/useDebounce.js

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

if (!eq(previousValue.current, value)) {
debounced.callback(value);
debounced(value);
previousValue.current = value;
}
}, [value, debounced, eq]);
return [state, { cancel: debounced.cancel, pending: debounced.pending, flush: debounced.flush }];
return [state, { cancel: debounced.cancel, isPending: debounced.isPending, flush: debounced.flush }];
}

@@ -11,3 +11,3 @@ export interface CallOptions {

flush: () => void;
pending: () => boolean;
isPending: () => boolean;
}

@@ -19,3 +19,3 @@ /**

export interface DebouncedState<T extends (...args: any[]) => ReturnType<T>> extends ControlFunctions {
callback: (...args: Parameters<T>) => ReturnType<T>;
(...args: Parameters<T>): ReturnType<T>;
}

@@ -53,8 +53,8 @@ /**

* @param {Object} [options={}] The options object.
* Specify invoking on the leading edge of the timeout.
* @param {boolean} [options.leading=false]
* Specify invoking on the leading edge of the timeout.
* The maximum time `func` is allowed to be delayed before it's invoked.
* @param {number} [options.maxWait]
* The maximum time `func` is allowed to be delayed before it's invoked.
* Specify invoking on the trailing edge of the timeout.
* @param {boolean} [options.trailing=true]
* Specify invoking on the trailing edge of the timeout.
* @returns {Function} Returns the new debounced function.

@@ -61,0 +61,0 @@ * @example

@@ -1,2 +0,2 @@

import { useRef, useCallback, useEffect, useMemo } from 'react';
import { useRef, useEffect, useMemo } from 'react';
/**

@@ -33,8 +33,8 @@ * Creates a debounced function that delays invoking `func` until after `wait`

* @param {Object} [options={}] The options object.
* Specify invoking on the leading edge of the timeout.
* @param {boolean} [options.leading=false]
* Specify invoking on the leading edge of the timeout.
* The maximum time `func` is allowed to be delayed before it's invoked.
* @param {number} [options.maxWait]
* The maximum time `func` is allowed to be delayed before it's invoked.
* Specify invoking on the trailing edge of the timeout.
* @param {boolean} [options.trailing=true]
* Specify invoking on the trailing edge of the timeout.
* @returns {Function} Returns the new debounced function.

@@ -87,64 +87,2 @@ * @example

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 = null;
lastInvokeTime.current = time;
return (result.current = funcRef.current.apply(thisArg, args));
}, []);
var startTimer = useCallback(function (pendingFunc, wait) {
if (useRAF)
cancelAnimationFrame(timerId.current);
timerId.current = useRAF ? requestAnimationFrame(pendingFunc) : setTimeout(pendingFunc, wait);
}, [useRAF]);
var shouldInvoke = useCallback(function (time) {
if (!mounted.current)
return false;
var timeSinceLastCall = time - lastCallTime.current;
var timeSinceLastInvoke = time - lastInvokeTime.current;
// Either this is the first call, activity has stopped and we're at the
// trailing edge, the system time has gone backwards and we're treating
// it as the trailing edge, or we've hit the `maxWait` limit.
return (!lastCallTime.current ||
timeSinceLastCall >= wait ||
timeSinceLastCall < 0 ||
(maxing && timeSinceLastInvoke >= maxWait));
}, [maxWait, maxing, wait]);
var trailingEdge = useCallback(function (time) {
timerId.current = null;
// Only invoke if we have `lastArgs` which means `func` has been
// debounced at least once.
if (trailing && lastArgs.current) {
return invokeFunc(time);
}
lastArgs.current = lastThis.current = null;
return result.current;
}, [invokeFunc, trailing]);
var timerExpired = useCallback(function () {
var time = Date.now();
if (shouldInvoke(time)) {
return trailingEdge(time);
}
// https://github.com/xnimorz/use-debounce/issues/97
if (!mounted.current) {
return;
}
// 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) {
useRAF ? cancelAnimationFrame(timerId.current) : clearTimeout(timerId.current);
}
lastInvokeTime.current = 0;
lastArgs.current = lastCallTime.current = lastThis.current = timerId.current = null;
}, [useRAF]);
var flush = useCallback(function () {
return !timerId.current ? result.current : trailingEdge(Date.now());
}, [trailingEdge]);
useEffect(function () {

@@ -156,42 +94,111 @@ mounted.current = true;

}, []);
var debounced = useCallback(function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
var time = Date.now();
var isInvoking = shouldInvoke(time);
lastArgs.current = args;
lastThis.current = _this;
lastCallTime.current = time;
if (isInvoking) {
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;
// You may have a question, why we have so many code under the useMemo definition.
//
// This was made as we want to escape from useCallback hell and
// not to initialize a number of functions each time useDebouncedCallback is called.
//
// It means that we have less garbage for our GC calls which improves performance.
// Also, it makes this library smaller.
//
// And the last reason, that the code without lots of useCallback with deps is easier to read.
// You have only one place for that.
var debounced = useMemo(function () {
var invokeFunc = function (time) {
var args = lastArgs.current;
var thisArg = lastThis.current;
lastArgs.current = lastThis.current = null;
lastInvokeTime.current = time;
return (result.current = funcRef.current.apply(thisArg, args));
};
var startTimer = function (pendingFunc, wait) {
if (useRAF)
cancelAnimationFrame(timerId.current);
timerId.current = useRAF ? requestAnimationFrame(pendingFunc) : setTimeout(pendingFunc, wait);
};
var shouldInvoke = function (time) {
if (!mounted.current)
return false;
var timeSinceLastCall = time - lastCallTime.current;
var timeSinceLastInvoke = time - lastInvokeTime.current;
// Either this is the first call, activity has stopped and we're at the
// trailing edge, the system time has gone backwards and we're treating
// it as the trailing edge, or we've hit the `maxWait` limit.
return (!lastCallTime.current ||
timeSinceLastCall >= wait ||
timeSinceLastCall < 0 ||
(maxing && timeSinceLastInvoke >= maxWait));
};
var trailingEdge = function (time) {
timerId.current = null;
// Only invoke if we have `lastArgs` which means `func` has been
// debounced at least once.
if (trailing && lastArgs.current) {
return invokeFunc(time);
}
if (maxing) {
// Handle invocations in a tight loop.
lastArgs.current = lastThis.current = null;
return result.current;
};
var timerExpired = function () {
var time = Date.now();
if (shouldInvoke(time)) {
return trailingEdge(time);
}
// https://github.com/xnimorz/use-debounce/issues/97
if (!mounted.current) {
return;
}
// 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);
};
var func = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
var time = Date.now();
var isInvoking = shouldInvoke(time);
lastArgs.current = args;
lastThis.current = _this;
lastCallTime.current = time;
if (isInvoking) {
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.
startTimer(timerExpired, wait);
return invokeFunc(lastCallTime.current);
}
}
if (!timerId.current) {
startTimer(timerExpired, wait);
return invokeFunc(lastCallTime.current);
}
}
if (!timerId.current) {
startTimer(timerExpired, wait);
}
return result.current;
}, [invokeFunc, leading, maxing, shouldInvoke, startTimer, timerExpired, wait]);
var pending = useCallback(function () {
return !!timerId.current;
}, []);
var debouncedState = useMemo(function () { return ({
callback: debounced,
cancel: cancel,
flush: flush,
pending: pending,
}); }, [debounced, cancel, flush, pending]);
return debouncedState;
return result.current;
};
func.cancel = function () {
if (timerId.current) {
useRAF ? cancelAnimationFrame(timerId.current) : clearTimeout(timerId.current);
}
lastInvokeTime.current = 0;
lastArgs.current = lastCallTime.current = lastThis.current = timerId.current = null;
};
func.isPending = function () {
return !!timerId.current;
};
func.flush = function () {
return !timerId.current ? result.current : trailingEdge(Date.now());
};
return func;
}, [leading, maxing, wait, maxWait, trailing, useRAF]);
return debounced;
}

@@ -24,8 +24,8 @@ "use strict";

if (!eq(previousValue.current, value)) {
debounced.callback(value);
debounced(value);
previousValue.current = value;
}
}, [value, debounced, eq]);
return [state, { cancel: debounced.cancel, pending: debounced.pending, flush: debounced.flush }];
return [state, { cancel: debounced.cancel, isPending: debounced.isPending, flush: debounced.flush }];
}
exports.default = useDebounce;

@@ -11,3 +11,3 @@ export interface CallOptions {

flush: () => void;
pending: () => boolean;
isPending: () => boolean;
}

@@ -19,3 +19,3 @@ /**

export interface DebouncedState<T extends (...args: any[]) => ReturnType<T>> extends ControlFunctions {
callback: (...args: Parameters<T>) => ReturnType<T>;
(...args: Parameters<T>): ReturnType<T>;
}

@@ -53,8 +53,8 @@ /**

* @param {Object} [options={}] The options object.
* Specify invoking on the leading edge of the timeout.
* @param {boolean} [options.leading=false]
* Specify invoking on the leading edge of the timeout.
* The maximum time `func` is allowed to be delayed before it's invoked.
* @param {number} [options.maxWait]
* The maximum time `func` is allowed to be delayed before it's invoked.
* Specify invoking on the trailing edge of the timeout.
* @param {boolean} [options.trailing=true]
* Specify invoking on the trailing edge of the timeout.
* @returns {Function} Returns the new debounced function.

@@ -61,0 +61,0 @@ * @example

@@ -35,8 +35,8 @@ "use strict";

* @param {Object} [options={}] The options object.
* Specify invoking on the leading edge of the timeout.
* @param {boolean} [options.leading=false]
* Specify invoking on the leading edge of the timeout.
* The maximum time `func` is allowed to be delayed before it's invoked.
* @param {number} [options.maxWait]
* The maximum time `func` is allowed to be delayed before it's invoked.
* Specify invoking on the trailing edge of the timeout.
* @param {boolean} [options.trailing=true]
* Specify invoking on the trailing edge of the timeout.
* @returns {Function} Returns the new debounced function.

@@ -89,64 +89,2 @@ * @example

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 = null;
lastInvokeTime.current = time;
return (result.current = funcRef.current.apply(thisArg, args));
}, []);
var startTimer = react_1.useCallback(function (pendingFunc, wait) {
if (useRAF)
cancelAnimationFrame(timerId.current);
timerId.current = useRAF ? requestAnimationFrame(pendingFunc) : setTimeout(pendingFunc, wait);
}, [useRAF]);
var shouldInvoke = react_1.useCallback(function (time) {
if (!mounted.current)
return false;
var timeSinceLastCall = time - lastCallTime.current;
var timeSinceLastInvoke = time - lastInvokeTime.current;
// Either this is the first call, activity has stopped and we're at the
// trailing edge, the system time has gone backwards and we're treating
// it as the trailing edge, or we've hit the `maxWait` limit.
return (!lastCallTime.current ||
timeSinceLastCall >= wait ||
timeSinceLastCall < 0 ||
(maxing && timeSinceLastInvoke >= maxWait));
}, [maxWait, maxing, wait]);
var trailingEdge = react_1.useCallback(function (time) {
timerId.current = null;
// Only invoke if we have `lastArgs` which means `func` has been
// debounced at least once.
if (trailing && lastArgs.current) {
return invokeFunc(time);
}
lastArgs.current = lastThis.current = null;
return result.current;
}, [invokeFunc, trailing]);
var timerExpired = react_1.useCallback(function () {
var time = Date.now();
if (shouldInvoke(time)) {
return trailingEdge(time);
}
// https://github.com/xnimorz/use-debounce/issues/97
if (!mounted.current) {
return;
}
// 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) {
useRAF ? cancelAnimationFrame(timerId.current) : clearTimeout(timerId.current);
}
lastInvokeTime.current = 0;
lastArgs.current = lastCallTime.current = lastThis.current = timerId.current = null;
}, [useRAF]);
var flush = react_1.useCallback(function () {
return !timerId.current ? result.current : trailingEdge(Date.now());
}, [trailingEdge]);
react_1.useEffect(function () {

@@ -158,43 +96,112 @@ mounted.current = true;

}, []);
var debounced = react_1.useCallback(function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
var time = Date.now();
var isInvoking = shouldInvoke(time);
lastArgs.current = args;
lastThis.current = _this;
lastCallTime.current = time;
if (isInvoking) {
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;
// You may have a question, why we have so many code under the useMemo definition.
//
// This was made as we want to escape from useCallback hell and
// not to initialize a number of functions each time useDebouncedCallback is called.
//
// It means that we have less garbage for our GC calls which improves performance.
// Also, it makes this library smaller.
//
// And the last reason, that the code without lots of useCallback with deps is easier to read.
// You have only one place for that.
var debounced = react_1.useMemo(function () {
var invokeFunc = function (time) {
var args = lastArgs.current;
var thisArg = lastThis.current;
lastArgs.current = lastThis.current = null;
lastInvokeTime.current = time;
return (result.current = funcRef.current.apply(thisArg, args));
};
var startTimer = function (pendingFunc, wait) {
if (useRAF)
cancelAnimationFrame(timerId.current);
timerId.current = useRAF ? requestAnimationFrame(pendingFunc) : setTimeout(pendingFunc, wait);
};
var shouldInvoke = function (time) {
if (!mounted.current)
return false;
var timeSinceLastCall = time - lastCallTime.current;
var timeSinceLastInvoke = time - lastInvokeTime.current;
// Either this is the first call, activity has stopped and we're at the
// trailing edge, the system time has gone backwards and we're treating
// it as the trailing edge, or we've hit the `maxWait` limit.
return (!lastCallTime.current ||
timeSinceLastCall >= wait ||
timeSinceLastCall < 0 ||
(maxing && timeSinceLastInvoke >= maxWait));
};
var trailingEdge = function (time) {
timerId.current = null;
// Only invoke if we have `lastArgs` which means `func` has been
// debounced at least once.
if (trailing && lastArgs.current) {
return invokeFunc(time);
}
if (maxing) {
// Handle invocations in a tight loop.
lastArgs.current = lastThis.current = null;
return result.current;
};
var timerExpired = function () {
var time = Date.now();
if (shouldInvoke(time)) {
return trailingEdge(time);
}
// https://github.com/xnimorz/use-debounce/issues/97
if (!mounted.current) {
return;
}
// 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);
};
var func = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
var time = Date.now();
var isInvoking = shouldInvoke(time);
lastArgs.current = args;
lastThis.current = _this;
lastCallTime.current = time;
if (isInvoking) {
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.
startTimer(timerExpired, wait);
return invokeFunc(lastCallTime.current);
}
}
if (!timerId.current) {
startTimer(timerExpired, wait);
return invokeFunc(lastCallTime.current);
}
}
if (!timerId.current) {
startTimer(timerExpired, wait);
}
return result.current;
}, [invokeFunc, leading, maxing, shouldInvoke, startTimer, timerExpired, wait]);
var pending = react_1.useCallback(function () {
return !!timerId.current;
}, []);
var debouncedState = react_1.useMemo(function () { return ({
callback: debounced,
cancel: cancel,
flush: flush,
pending: pending,
}); }, [debounced, cancel, flush, pending]);
return debouncedState;
return result.current;
};
func.cancel = function () {
if (timerId.current) {
useRAF ? cancelAnimationFrame(timerId.current) : clearTimeout(timerId.current);
}
lastInvokeTime.current = 0;
lastArgs.current = lastCallTime.current = lastThis.current = timerId.current = null;
};
func.isPending = function () {
return !!timerId.current;
};
func.flush = function () {
return !timerId.current ? result.current : trailingEdge(Date.now());
};
return func;
}, [leading, maxing, wait, maxWait, trailing, useRAF]);
return debounced;
}
exports.default = useDebouncedCallback;
{
"name": "use-debounce",
"version": "5.2.1",
"version": "6.0.0-beta",
"description": "Debounce hook for react",

@@ -5,0 +5,0 @@ "main": "lib/index.js",

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