A debounce hook for react

Overview

Features

Install

yarn add use-debounce
# or
npm i use-debounce --save

Demos

The simplest way to start playing around with use-debounce is with this CodeSandbox snippet: https://codesandbox.io/s/kx75xzyrq7

More complex example with searching for matching countries using debounced input: https://codesandbox.io/s/rr40wnropq (thanks to https://twitter.com/ZephDavies)

Changelog

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

Simple values debouncing

According to https://twitter.com/dan_abramov/status/1060729512227467264

import React, { useState } from 'react';
import { useDebounce } from 'use-debounce';

export default function Input() {
  const [text, setText] = useState('Hello');
  const [value] = useDebounce(text, 1000);

  return (
    <div>
      <input
        defaultValue={'Hello'}
        onChange={(e) => {
          setText(e.target.value);
        }}
      />
      <p>Actual value: {text}</p>
      <p>Debounce value: {value}</p>
    </div>
  );
}

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

import { useDebouncedCallback } from 'use-debounce';

function Input({ defaultValue }) {
  const [value, setValue] = useState(defaultValue);
  // Debounce callback
  const debounced = useDebouncedCallback(
    // function
    (value) => {
      setValue(value);
    },
    // delay in ms
    1000
  );

  // you should use `e => debounced.callback(e.target.value)` as react works with synthetic events
  return (
    <div>
      <input defaultValue={defaultValue} onChange={(e) => debounced.callback(e.target.value)} />
      <p>Debounced value: {value}</p>
    </div>
  );
}

Example with Scroll (and native event listeners): https://codesandbox.io/s/32yqlyo815

function ScrolledComponent() {
  // just a counter to show, that there are no any unnessesary updates
  const updatedCount = useRef(0);
  updatedCount.current++;

  const [position, setPosition] = useState(window.pageYOffset);

  // Debounce callback
  const debounced = useDebouncedCallback(
    // function
    () => {
      setPosition(window.pageYOffset);
    },
    // delay in ms
    800
  );

  useEffect(() => {
    const unsubscribe = subscribe(window, 'scroll', debounced.callback);
    return () => {
      unsubscribe();
    };
  }, []);

  return (
    <div style={{ height: 10000 }}>
      <div style={{ position: 'fixed', top: 0, left: 0 }}>
        <p>Debounced top position: {position}</p>
        <p>Component rerendered {updatedCount.current} times</p>
      </div>
    </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:

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

Cancel, maxWait and memoization

  1. Both useDebounce and useDebouncedCallback works with maxWait option. This params describes the maximum time func is allowed to be delayed before it's invoked.
  2. You can cancel debounce cycle, by calling cancel callback

The full example you can see here https://codesandbox.io/s/4wvmp1xlw4

import React, { useState, useCallback } from 'react';
import ReactDOM from 'react-dom';
import { useDebouncedCallback } from 'use-debounce';

function Input({ defaultValue }) {
  const [value, setValue] = useState(defaultValue);
  const debounced = useDebouncedCallback(
    (value) => {
      setValue(value);
    },
    500,
    // The maximum time func is allowed to be delayed before it's invoked:
    { maxWait: 2000 }
  );

  // you should use `e => debounced.callback(e.target.value)` as react works with synthetic events
  return (
    <div>
      <input defaultValue={defaultValue} onChange={(e) => debounced.callback(e.target.value)} />
      <p>Debounced value: {value}</p>
      <button onClick={debounced.cancel}>Cancel Debounce cycle</button>
    </div>
  );
}

const rootElement = document.getElementById('root');
ReactDOM.render(<Input defaultValue="Hello world" />, rootElement);

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.

import React, { useState, useCallback } from 'react';
import { useDebouncedCallback } from 'use-debounce';

function InputWhichFetchesSomeData({ defaultValue, asyncFetchData }) {
  const debounced = useDebouncedCallback(
    (value) => {
      asyncFetchData;
    },
    500,
    { maxWait: 2000 }
  );

  // When the component goes to be unmounted, we will fetch data if the input has changed.
  useEffect(
    () => () => {
      debounced.flush();
    },
    [debounced]
  );

  return <input defaultValue={defaultValue} onChange={(e) => debounced.callback(e.target.value)} />;
}

Pending method

pending method shows whether component has pending callbacks. Works for both useDebounce and useDebouncedCallback:

function Component({ text }) {
  const debounced = useDebouncedCallback(useCallback(() => {}, []), 500);

  expect(debounced.pending()).toBeFalsy();
  debounced.callback();
  expect(debounced.pending()).toBeTruthy();
  debounced.flush();
  expect(debounced.pending()).toBeFalsy();

  return <span>{text}</span>;
}

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

import React, { useState } from 'react';
import { useDebounce } from 'use-debounce';

export default function Input() {
  const [text, setText] = useState('Hello');
  const [value] = useDebounce(text, 1000, { leading: true });

  // value is updated immediately when text changes the first time,
  // but all subsequent changes are debounced.
  return (
    <div>
      <input
        defaultValue={'Hello'}
        onChange={(e) => {
          setText(e.target.value);
        }}
      />
      <p>Actual value: {text}</p>
      <p>Debounce value: {value}</p>
    </div>
  );
}

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 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:

  1. Avoid excessively updating the position while scrolling.

    const scrollHandler = useThrottledCallback(updatePosition, 100);
    window.addEventListener('scroll', scrollHandler);
  2. Invoke renewToken when the click event is fired, but not more than once every 5 minutes.

    const throttled = useThrottledCallback(renewToken, 300000, { 'trailing': false })
    <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.

Issues
  • Optimization: Escape from useCallback hell

    Optimization: Escape from useCallback hell

    Discussion/Proposal

    The specs are failing now because they are created for the current realization. But actually, I'm not sure that the current realization is the best we can do.

    Since your library returns callbacks only it doesn't make sense to update/lose a link to debouncedState at all.

    So I created a version where debouncedState is always memorized. It also makes code way simpler and saves us 57 bytes.

    Thought?

    opened by omgovich 10
  • How to use debounce for EventListeners?

    How to use debounce for EventListeners?

    Example:

    const windowSizes = useDebounce(window.pageYOffset, 1000)
      const handleScroll = event => {
        //how to debounse windowSizes change?
      }
    
    
      useEffect(() => {
        window.addEventListener('scroll', handleScroll)
    
        return () => {
          window.removeEventListener('scroll', handleScroll)
        }
      }, [])
    
    question 
    opened by ZiiMakc 8
  • Bad example for useDebouncedCallback in README

    Bad example for useDebouncedCallback in README

    in the readme example of useDebouncedCallback you have:

     const debounced = useDebouncedCallback(
        // function
        (value) => {
          setValue(value);
        },
        // delay in ms
        1000
      );
    

    But it's returning an array, so it really should be

    const [debounced] = useDebouncedCallback(

    opened by TonisPiip 8
  • Infinite startTimer loop causing high CPU load

    Infinite startTimer loop causing high CPU load

    Hello!

    I'm not able to give exact reproduction steps, but this screenshot demonstrates the problem: image

    I'm using useDebouncedCallback in a regular component. The component itself is not re-rendered, and there is nothing that could call the callback itself.

    Version of React: 16.9.46

    Thanks for help!

    opened by gtanczyk 8
  • Slight confusion between v4 `callPending` (function) and new `pending` (boolean)

    Slight confusion between v4 `callPending` (function) and new `pending` (boolean)

    Hi there, first of all, thanks for providing support and putting so much effort into this hook. I'm using it in production code and it works like a charm, love the simplicity!

    While the adoption for v5 is not as widespread, what do you think of renaming debounced.pending() to debounced.isPending()?

    I was dealing with a bug where I was calling debounce.pending() instead of flush() as I was used to the old v4 names, and I had to read the documentation twice to realize to realize my mistake (it was, in the end, my mistake, fully aware of that).

    I feel that some packages adopting the isBoolean() approach makes it more clear for developers. Of course, it is just a suggestion.

    Again, thank you for your work!

    Yuan

    opened by yuanworks 8
  • useDebounce is broken

    useDebounce is broken

    I'll try to explain what's going on. I copy pasted the source code and marked some lines with comments so that I can refer to them while explaining.

          functionTimeoutHandler.current = setTimeout(() => {
            if (!isComponentUnmounted.current) {
              // MARKER: X
              debouncedFunction.apply(null, arguments);
            }
            // MARKER: Z
            cancelDebouncedCallback();
          }, delay);
    
      React.useEffect(() => {
        if (debouncedState[0] !== value) {
          // MARKER: Y
          debouncedCallback[0](value);
        }
      });
    

    Steps 2-6 happen in the same event loop.

    1. Value updates. Timeout is scheduled.
    2. X is triggered. It rerenders the component synchronously.
    3. Y is triggered, but for the closure of previous render. debouncedState[0] and value have different values. Y reschedules a timeout. Remember that we are still in the call stack of "Step 1".
    4. Funny enough, Y is triggered again. This time, it is for the closure of current render. debouncedState[0] and value have different values. Y reschedules a timeout. This step is actually not needed for a bug to occur. Step 3 is enough.
    5. Call stack rewinds up and we are back in "Step 1". The next line is Z.
    6. Z is triggered, cancelling all previously scheduled timeouts in steps 3 and 4.

    Possible solution:

    First, I suggest using eslint-plugin-react-hooks and sticking to its rules. Otherwise it's too easy to make mistakes. Second, I think trying to save a few hundred bytes is unnecessary. It takes a lot away from code readability.

    export default function useDebounce(value, delay, options = {}) {
      const [state, dispatch] = React.useState(value);
      const [callback, cancel] = useDebouncedCallback(useCallback((value) => dispatch(value), []), delay, options);
    
      React.useEffect(() => {
        callback(value);
      }, [callback, value]);
    
      return [state, cancel];
    }
    
    
    opened by anilanar 7
  • Would be great to configure trailing

    Would be great to configure trailing

    Lodash's implementation of debounce has a trailing option which is necessary to specify in some cases: https://lodash.com/docs/4.17.15#debounce

    It would be nice to have that option for this library.

    opened by scottmas 7
  • 5.0.3 — useDebouncedCallback export issue

    5.0.3 — useDebouncedCallback export issue

    Hey, firstly thank you for your work on the package, appreciate it.

    There is an issue in the latest version 5.0.3, it seems like useDebouncedCallback hasn't been exported properly

    ModuleNotFoundError: Module not found: Error: Package path ./lib/useDebouncedCallback is not exported from package /node_modules/use-debounce (see exports field in /node_modules/use-debounce/package.json)
    
    opened by kamranahmedse 6
  • Complete support for leading, trailing, maxWait

    Complete support for leading, trailing, maxWait

    This PR

    • Addresses https://github.com/xnimorz/use-debounce/issues/60
    • Changes useDebouncedCallback to mirror lodash's implementation of debounce.
    • Support using rAF when omitting wait
    • Ability to implement throttling without trailing edge call
      • wait: 200, {leading: true, trailing: false, maxWait: 200}

    This is a lot of changes to the source code but it was easier to start with lodash code and work backwards from there. Let me know what you think.

    Things to note

    • The requestAnimationFrame is accessed via window.requestAnimationFrame. I'm not an experienced library author so I'm not sure if this is safe in all contexts (server side rendering, etc.). Looks like lodash uses https://github.com/lodash/lodash/blob/master/.internal/root.js to choose the right global object. I guess this is infamously painful in the JS ecosystem :)
    opened by tryggvigy 6
  • How to restore the behavior of v3 in v4?

    How to restore the behavior of v3 in v4?

    How do I preserve the old behavior from version 3? The PR #62 introduced new options, but I tried various combinations of the flags and none gave the old effect. Is this even possible? Maybe the current behavior relies on bugs that I should fix? Am I stuck with v3 now?

    Context: Just spent 2 hours to pinpoint my new form validation errors to the upgrade of use-debounce to version 4.0.0. The funny consequence is that depending on new options' values of use-debounce, yup (form validation library) either throws errors for all form fields in the form, where messages are just valid field values (probably timing-related), or does not seem to be running at all.

    Repro: I don't have a minimal example, but this is the snippet that breaks in my app: https://github.com/neherlab/covid19_scenarios/blob/d12969d1cef3c07abb3d54b914c38001aec851e2/src/components/Main/Main.tsx#L119-L153 Reproducible by upgrading "use-debounce" to "4.0.0" and then changing any form value.

    cc: @tryggvigy

    Thanks for your help!

    opened by ivan-aksamentov 6
  • wrap state controller object to useMemo

    wrap state controller object to useMemo

    the reference will remain unchanged between renders

    it fixes #121

    opened by msharifi99 0
  • value controller reference changes on every render

    value controller reference changes on every render

    Describe the bug the reference of value controller object returned by useDebounce keep changing on every render in consumer component. and it cause hooks that use the object as their dependencies to re-call.

    Expected behavior to reference does not change across re-renderes.

    use-debounce version: ^7.0.0

    opened by msharifi99 0
  • Bump tmpl from 1.0.4 to 1.0.5

    Bump tmpl from 1.0.4 to 1.0.5

    Bumps tmpl from 1.0.4 to 1.0.5.

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • ` useDebouncedCallback` does not have ` equalityFn` option in the type definition.

    ` useDebouncedCallback` does not have ` equalityFn` option in the type definition.

    Describe the bug useDebouncedCallback does not have equalityFn option defined in the type definition.

    In documentation, it says both useDebounce and useDebouncedCallback have equalityFn provided. image

    Looking at the Type definition, and Options does not have equalityFn defined. image

    Admittedly, I haven't looked into src code to see if equalityFn logic is actually available to useDebouncedCallback, but if it is, then this is simply a type definition issue. From documentation, it seems like both useDebounce and useDebouncedCallback share options, so they should also share a type, which they currently are not.

    I may come back to investigate/resolve this in a bit, but busy with some other things right now.

    use-debounce version: 7.0.0

    opened by harrisonywu 2
Releases(7.0.0)
  • 7.0.0(Jun 20, 2021)

    • breakng change useDebounce hook changed isPending behavior from async reacting to the sync. Now isPending returns True as soon as the new value is sent to the hook: Example is here: https://github.com/xnimorz/use-debounce/blob/master/test/useDebounce.test.tsx#L303-L329

    • Dev dependencies updated

    Source code(tar.gz)
    Source code(zip)
  • 6.0.1(Apr 3, 2021)

  • 6.0(Mar 7, 2021)

    • breakind change: removed callback field, instead of this useDebouncedCallback and useThrottledCallback returns a callable function: Old:

      const { callback, pending } = useDebouncedCallback(/*...*/);
      // ...
      debounced.callback();
      

      New:

      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:

      const { callback, pending } = useDebouncedCallback(/*...*/);
      

      New:

      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

    Source code(tar.gz)
    Source code(zip)
  • 5.2.1(Feb 20, 2021)

    • prevent having ininite setTimeout setup when component gets unmounted https://github.com/xnimorz/use-debounce/issues/97
    • function type works correctly with useDebounce now. https://github.com/xnimorz/use-debounce/pull/95 Thanks to @csu-feizao
    Source code(tar.gz)
    Source code(zip)
  • 5.2.0(Dec 11, 2020)

  • 5.0.1(Sep 29, 2020)

  • 5.0.0(Sep 19, 2020)

    • breaking change: Now useDebouncedCallback returns an object instead of array:

      Old:

      const [debouncedCallback, cancelDebouncedCallback, callPending] = useDebouncedCallback(/*...*/);
      

      New:

      const debounced = useDebouncedCallback(/*...*/);
      /**
       * debounced: {
       *   callback: (...args: T) => unknown, which is debouncedCallback
       *   cancel: () => void, which is cancelDebouncedCallback
       *   flush: () => void, which is callPending
       *   pending: () => boolean, which is a new function
       * } 
       */
      
    • breaking change: Now useDebounce returns an array of 2 fields instead of a plain array: Old:

      const [value, cancel, callPending] = useDebounce(/*...*/);
      

      New:

      const [value, fn] = useDebouncedCallback(/*...*/);
      /**
       * value is just a value without changes
       * But fn now is an object: { 
       *   cancel: () => void, which is cancel
       *   flush: () => void, which is callPending
       *   pending: () => boolean, which is a new function
       * } 
       */
      
    • Added pending function to both useDebounce and useDebouncedCallback which shows whether component has pending callbacks Example:

      function Component({ text }) {
        const debounced = useDebouncedCallback(useCallback(() => {}, []), 500);
      
        expect(debounced.pending()).toBeFalsy();
        debounced.callback();
        expect(debounced.pending()).toBeTruthy();
        debounced.flush();
        expect(debounced.pending()).toBeFalsy();
      
        return <span>{text}</span>;
      }
      

    For more details of these major changes you could check this commit https://github.com/xnimorz/use-debounce/commit/1b4ac0432f7074248faafcfe6248df0be4bb4af0 and this issue https://github.com/xnimorz/use-debounce/issues/61

    • Fixed security alerts
    Source code(tar.gz)
    Source code(zip)
  • 4.0.0(Sep 19, 2020)

    • breaking change: Support lodash style throttling options for trailing+maxWidth. Thanks to @tryggvigy Example:
    useDebouncedCallback(callback, 300, {
      leading: true,
      trailing: false,
      maxWait: 300,
    })
    

    Where the trailing edge is turned off. Let's say the function is called twice in the first 300ms. Now debounced function to have been called once.

    how to migrate: Please, check your traling: false params with maxWait option

    • breaking change: Now in case delay option is unset, it will be requestAnimationFrame delay

    • breaking change: Now debouncedCallback from useDebouncedCallback returns a value. In v3 it used to return undefined:

    Source code(tar.gz)
    Source code(zip)
  • 3.2.0(Dec 1, 2019)

    3.2.0

    • useDebounce has callPending method. See https://github.com/xnimorz/use-debounce/blob/master/test/useDebounce.test.tsx#L276-L302 unit test for examples.

    3.1.0

    • Now package includes only nessesary files. Thanks to @vkrol
    • Added optional equalityFn to options object for useDebounce so that you can provide a custom equality function to the hook. Thanks to @seruco

    3.0.1

    • Added missed esm directory (thanks for reporting @FredyC)
    • Fixed import name (thanks for PR @neoromantic)
    • Updated eslint-utils lib version due to security issue

    3.0.0

    • breaking change now, cache file renamed to useDebounce and callback file renamed to useDebouncedCallback. If you used to import file by its path:
    import useDebounce from 'use-debounce/lib/cache';
    import useDebouncedCallback from 'use-debounce/lib/callback';
    

    it should be renamed to

    import useDebounce from 'use-debounce/lib/useDebounce';
    import useDebouncedCallback from 'use-debounce/lib/useDebouncedCallback';
    

    It helps us to keep more descriptive names. Thanks to @vkrol https://github.com/xnimorz/use-debounce/pull/33

    • breaking change now, useDebouncedCallback executes the latest callback, which was sent to the hook (thanks for the report @alexandr-bbm https://github.com/xnimorz/use-debounce/issues/35) https://github.com/xnimorz/use-debounce/commit/eca14cc25b1f14bdd337a555127fd98c54ab7a5c

    • code shipped in ESM format. Thanks to @vkrol https://github.com/xnimorz/use-debounce/pull/34

    Source code(tar.gz)
    Source code(zip)
  • 2.1.0(Jun 4, 2019)

  • 2.0.0(Apr 27, 2019)

    • breaking changes now, useDebounceCallback doesn't have deps argument. If you want to cache your callback it's better to use:
    const myCallback = useDebouncedCallback(
      useCallback(() => {
        /* do some stuff */
      }, [value]),
      500
    );
    
    • added size-limit to the project.
    • Reduce size of the library from 705 bytes to 352 bytes (50%)
    Source code(tar.gz)
    Source code(zip)
  • 1.1.1(Mar 9, 2019)

    • add callPending callback to useDebouncedCallback 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.
    import React, { useState, useCallback } from 'react';
    import useDebouncedCallback from 'use-debounce/lib/callback';
    
    function InputWhichFetchesSomeData({ defaultValue, asyncFetchData }) {
      const [debouncedFunction, cancel, callPending] = useDebouncedCallback(
        (value) => {
          asyncFetchData;
        },
        500,
        [],
        { maxWait: 2000 }
      );
    
      // When the component goes to be unmounted, we will fetch data if the input has changed.
      useEffect(
        () => () => {
          callPending();
        },
        []
      );
    
      return <input defaultValue={defaultValue} onChange={(e) => debouncedFunction(e.target.value)} />;
    }
    

    More examples are available here: https://github.com/xnimorz/use-debounce/commit/989d6c0efb4eef080ed78330233186d7b0c249e3#diff-c7e0cfdec8acc174d3301ff43b986264R196

    Source code(tar.gz)
    Source code(zip)
  • 1.0.0(Feb 27, 2019)

    The full example: https://codesandbox.io/s/4wvmp1xlw4

    • add maxWait option. The maximum time func is allowed to be delayed before it's invoked.
    • add cancel callback (thanks to @thibaultboursier or contributing). Cancel callback removes func from the queue (even maxWait).
    • [BREAKING] change the contact of use-debounce callback and value hooks:

    Old:

    import { useDebounce, useDebouncedCallback } from 'use-debounce';
    
    ...
    const debouncedValue = useDebounce(value, 1000);
    const debouncedCallback = useDebouncedCallback(() => {...}, 1000);
    

    New:

    import { useDebounce, useDebouncedCallback } from 'use-debounce';
    
    ...
    const [ debouncedValue, cancelValueDebouncingCycle ] = useDebounce(value, 1000);
    const [ debouncedCallback, cancelCallback ] = useDebouncedCallback(() => {...}, 1000);
    

    You still can use only value and callback:

    import { useDebounce, useDebouncedCallback } from 'use-debounce';
    
    ...
    const [ debouncedValue ] = useDebounce(value, 1000);
    const [ debouncedCallback ] = useDebouncedCallback(() => {...}, 1000);
    
    Source code(tar.gz)
    Source code(zip)
Owner
Nik Mostovoy
Just a frontend engineer ¯\_(ツ)_/¯ Like react, svelte. Interested in architecture, infra, and performance. Author of https://boarder.app
Nik Mostovoy
React hook to handle any async operation in React components, and prevent race conditions

React-async-hook This library only does one small thing, and does it well. Don't expect it to grow in size, because it is feature complete: Handle fet

Sébastien Lorber 852 Sep 16, 2021
Essential React custom hooks ⚓ to super charge your components!

Essential React custom hooks ⚓ to super charge your components!

Bhargav Ponnapalli 1.8k Sep 24, 2021
Custom React hooks for your project.

Captain hook Overview Here is a modest list of hooks that I use every day. I will add more in the next few days, keep watching. And if you have some g

Steven Persia 336 Sep 24, 2021
React hook library, ready to use, written in Typescript.

This is the repository for usehooks.ts, a Gatsby powered blog hosted with Github & netlify that publishes easy to understand React Hook code snippets.

Julien 473 Sep 23, 2021
😎 📍 React hook for Google Maps Places Autocomplete.

USE-PLACES-AUTOCOMPLETE This is a React hook for Google Maps Places Autocomplete, which helps you build a UI component with the feature of place autoc

Welly 866 Sep 20, 2021
Checks whether a Ref has scrolled into view or not.

@rehooks/visibility-sensor DEPRECATED. Moved to @rooks/use-visibility-sensor React hook for visibility sensing a ref It checks whether an element has

Bhargav Ponnapalli 13 Apr 17, 2020
Testing hooks with Jest

Jooks (Jest ❤ + Hooks ????) If you're going through hell testing React Hooks, keep going. (Churchill) What are Custom React Hooks React Hooks are a ne

Antoine Jaussoin 73 Aug 10, 2021
A React.js global state manager with Hooks

A React.js global state manager with Hooks

Lorenzo Spinelli 60 Sep 13, 2021
🐭 React hook that tracks mouse events on selected element - zero dependencies

React Mighty Mouse React hook that tracks mouse events on selected element. Demo Demos created with React DemoTab ?? Install npm install react-hook-mi

mkosir 85 Sep 6, 2021
🧘Managed, cancelable and safely typed requests.

Managed, cancelable and safely typed requests. Table of Contents Install Quick Start Usage useResource useRequest request() createRequestError() Type

Matheus Schettino 111 Aug 19, 2021
React hook for conveniently use Fetch API

react-fetch-hook React hook for conveniently use Fetch API. Tiny (556 B). Calculated by size-limit Both Flow and TypeScript types included import Reac

Ilya Lesik 301 Aug 30, 2021
use css in js with react hook.

style-hook easy to write dynamic css features use css in react hook easy to get started install use npm npm i -S style-hook or use yarn yarn add style

null 15 Sep 1, 2021
Easily manage the Google Tag Manager via Hook

React Google Tag Manager Hook Use easily the Google Tag Manager With this custom hook, you can easily use the Google Tag Manager with 0 config, you ju

Guido Porcaro 97 Sep 10, 2021
😎 ♻️ A tiny React hook for rendering large datasets like a breeze.

?? ♻️ A tiny React hook for rendering large datasets like a breeze.

Welly 805 Sep 13, 2021
⚛️ Minimal "optimistic UI" pattern implementation with a React Hook

react-optimistic-ui-hook Minimal zero dependency "optimistic UI" pattern implementation in a React Hook. What is "Optimistic UI"? Optimistic UIs don’t

Mohamad Jahani 21 Sep 7, 2021
React hook for using keyboard shortcuts in components.

react-hotkeys-hook React hook for using keyboard shortcuts in components. This is a hook version for the hotkeys package. Documentation and live examp

Johannes Klauss 820 Sep 23, 2021
⚛️ A React Hook to monitor changes in the size of an element using native ResizeObserver API 🔍

⚛️ A React Hook to monitor changes in the size of an element using native ResizeObserver API ??

Gautam Arora 20 Sep 11, 2021
Understand how React-hook really behaves, once and for all!

Understand how React-hook really behaves, once and for all!

null 61 Sep 7, 2021
React Redux binding with React Hooks and Proxy

There are several projects related to this repo. Here's the index of those. reactive-react-redux v5-alpha (this repo): This has an experimental react-

Daishi Kato 503 Sep 6, 2021