{"id":13450700,"url":"https://github.com/xnimorz/use-debounce","last_synced_at":"2025-05-06T02:58:12.752Z","repository":{"id":38788980,"uuid":"156849227","full_name":"xnimorz/use-debounce","owner":"xnimorz","description":"A debounce hook for react","archived":false,"fork":false,"pushed_at":"2025-04-15T21:07:41.000Z","size":1397,"stargazers_count":3184,"open_issues_count":6,"forks_count":113,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-05-06T02:58:07.583Z","etag":null,"topics":["debounce","react","react-hook","react-hooks","react-use","usedebounce"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/xnimorz.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2018-11-09T10:50:43.000Z","updated_at":"2025-05-04T15:47:10.000Z","dependencies_parsed_at":"2023-02-09T13:46:48.502Z","dependency_job_id":"3299f77c-bd27-452e-8a05-c369409a1fc8","html_url":"https://github.com/xnimorz/use-debounce","commit_stats":{"total_commits":235,"total_committers":36,"mean_commits":6.527777777777778,"dds":0.5234042553191489,"last_synced_commit":"453490e4119ab36b0dfbb1f1bfd742d7ca06a4d8"},"previous_names":[],"tags_count":26,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xnimorz%2Fuse-debounce","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xnimorz%2Fuse-debounce/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xnimorz%2Fuse-debounce/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xnimorz%2Fuse-debounce/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xnimorz","download_url":"https://codeload.github.com/xnimorz/use-debounce/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252612465,"owners_count":21776255,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["debounce","react","react-hook","react-hooks","react-use","usedebounce"],"created_at":"2024-07-31T07:00:37.424Z","updated_at":"2025-05-06T02:58:12.733Z","avatar_url":"https://github.com/xnimorz.png","language":"TypeScript","funding_links":[],"categories":["TypeScript","Packages","Asynchronous operations"],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003ca href=\"https://www.npmjs.com/package/use-debounce\"\u003e\n    \u003cimg src=\"logo.png\" width=\"500\" alt=\"use-debounce\" /\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003ca href=\"https://www.npmjs.com/package/use-debounce\"\u003e\n    \u003cimg alt=\"npm\" src=\"https://img.shields.io/npm/v/use-debounce.svg?labelColor=49516F\u0026color=8994BC\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://npmjs.org/package/use-debounce\"\u003e\n    \u003cimg alt=\"downloads\" src=\"https://badgen.net/npm/dm/use-debounce?labelColor=49516F\u0026color=8994BC\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://bundlephobia.com/result?p=use-debounce\"\u003e\n    \u003cimg alt=\"tree-shakeable\" src=\"https://badgen.net/bundlephobia/tree-shaking/use-debounce?labelColor=49516F\u0026color=8994BC\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://npmjs.org/package/use-debounce\"\u003e\n    \u003cimg alt=\"types included\" src=\"https://badgen.net/npm/types/use-debounce?labelColor=49516F\u0026color=8994BC\" /\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\n# useDebounce, useDebouncedCallback \u0026 useThrottledCallback\n\nReact libraries for debouncing without tears!\n\n- Small size \u003c 1 Kb\n- Compatible with underscore / lodash impl — learn once, use everywhere\n- Server-rendering friendly!\n\n## Features\n\n- [classic debounced callback](#debounced-callbacks)\n- [**value** debouncing](#simple-values-debouncing)\n- [cancel, maxWait and memoization](#advanced-usage)\n\n## Install\n\n```sh\nyarn add use-debounce\n# or\nnpm i use-debounce --save\n```\n\n## Copy paste guidance:\n\n### use-debounce\n\nSimple usage: https://codesandbox.io/s/kx75xzyrq7\n\nDebounce HTTP request: https://codesandbox.io/s/rr40wnropq\n\nDebounce HTTP request with `leading` param: https://codesandbox.io/s/cache-example-with-areas-and-leading-param-119r3i\n\n### use-debounce callback\n\nSimple usage: https://codesandbox.io/s/x0jvqrwyq\n\nCombining with native event listeners: https://codesandbox.io/s/32yqlyo815\n\nCancelling, maxWait and memoization: https://codesandbox.io/s/4wvmp1xlw4\n\nHTTP requests: https://codesandbox.io/s/use-debounce-callback-http-y1h3m6\n\n## Changelog\n\nhttps://github.com/xnimorz/use-debounce/blob/master/CHANGELOG.md\n\n## Simple values debouncing\n\nAccording to https://twitter.com/dan_abramov/status/1060729512227467264\nWebArchive link: https://web.archive.org/web/20210828073432/https://twitter.com/dan_abramov/status/1060729512227467264\n\n```javascript\nimport React, { useState } from 'react';\nimport { useDebounce } from 'use-debounce';\n\nexport default function Input() {\n  const [text, setText] = useState('Hello');\n  const [value] = useDebounce(text, 1000);\n\n  return (\n    \u003cdiv\u003e\n      \u003cinput\n        defaultValue={'Hello'}\n        onChange={(e) =\u003e {\n          setText(e.target.value);\n        }}\n      /\u003e\n      \u003cp\u003eActual value: {text}\u003c/p\u003e\n      \u003cp\u003eDebounce value: {value}\u003c/p\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\nThis 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:\n\n## Debounced callbacks\n\nBesides `useDebounce` for values you can debounce callbacks, that is the more commonly understood kind of debouncing.\nExample with Input (and react callbacks): https://codesandbox.io/s/x0jvqrwyq\n\n```js\nimport { useDebouncedCallback } from 'use-debounce';\n\nfunction Input({ defaultValue }) {\n  const [value, setValue] = useState(defaultValue);\n  // Debounce callback\n  const debounced = useDebouncedCallback(\n    // function\n    (value) =\u003e {\n      setValue(value);\n    },\n    // delay in ms\n    1000\n  );\n\n  // you should use `e =\u003e debounced(e.target.value)` as react works with synthetic events\n  return (\n    \u003cdiv\u003e\n      \u003cinput\n        defaultValue={defaultValue}\n        onChange={(e) =\u003e debounced(e.target.value)}\n      /\u003e\n      \u003cp\u003eDebounced value: {value}\u003c/p\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\nExample with Scroll (and native event listeners): https://codesandbox.io/s/32yqlyo815\n\n```js\nfunction ScrolledComponent() {\n  // just a counter to show, that there are no any unnessesary updates\n  const updatedCount = useRef(0);\n  updatedCount.current++;\n\n  const [position, setPosition] = useState(window.pageYOffset);\n\n  // Debounce callback\n  const debounced = useDebouncedCallback(\n    // function\n    () =\u003e {\n      setPosition(window.pageYOffset);\n    },\n    // delay in ms\n    800\n  );\n\n  useEffect(() =\u003e {\n    const unsubscribe = subscribe(window, 'scroll', debounced);\n    return () =\u003e {\n      unsubscribe();\n    };\n  }, []);\n\n  return (\n    \u003cdiv style={{ height: 10000 }}\u003e\n      \u003cdiv style={{ position: 'fixed', top: 0, left: 0 }}\u003e\n        \u003cp\u003eDebounced top position: {position}\u003c/p\u003e\n        \u003cp\u003eComponent rerendered {updatedCount.current} times\u003c/p\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n### Returned value from `debounced()`\n\nSubsequent calls to the debounced function `debounced` return the result of the last func invocation.\nNote, that if there are no previous invocations it's mean you will get undefined. You should check it in your code properly.\n\nExample:\n\n```javascript\nit('Subsequent calls to the debounced function `debounced` return the result of the last func invocation.', () =\u003e {\n  const callback = jest.fn(() =\u003e 42);\n\n  let callbackCache;\n  function Component() {\n    const debounced = useDebouncedCallback(callback, 1000);\n    callbackCache = debounced;\n    return null;\n  }\n  Enzyme.mount(\u003cComponent /\u003e);\n\n  const result = callbackCache();\n  expect(callback.mock.calls.length).toBe(0);\n  expect(result).toBeUndefined();\n\n  act(() =\u003e {\n    jest.runAllTimers();\n  });\n  expect(callback.mock.calls.length).toBe(1);\n  const subsequentResult = callbackCache();\n\n  expect(callback.mock.calls.length).toBe(1);\n  expect(subsequentResult).toBe(42);\n});\n```\n\n### Advanced usage\n\n#### Cancel, maxWait and memoization\n\n1. Both `useDebounce` and `useDebouncedCallback` works with `maxWait` option. This params describes the maximum time func is allowed to be delayed before it's invoked.\n2. You can cancel debounce cycle, by calling `cancel` callback\n\nThe full example you can see here https://codesandbox.io/s/4wvmp1xlw4\n\n```javascript\nimport React, { useState } from 'react';\nimport ReactDOM from 'react-dom';\nimport { useDebouncedCallback } from 'use-debounce';\n\nfunction Input({ defaultValue }) {\n  const [value, setValue] = useState(defaultValue);\n  const debounced = useDebouncedCallback(\n    (value) =\u003e {\n      setValue(value);\n    },\n    500,\n    // The maximum time func is allowed to be delayed before it's invoked:\n    { maxWait: 2000 }\n  );\n\n  // you should use `e =\u003e debounced(e.target.value)` as react works with synthetic events\n  return (\n    \u003cdiv\u003e\n      \u003cinput\n        defaultValue={defaultValue}\n        onChange={(e) =\u003e debounced(e.target.value)}\n      /\u003e\n      \u003cp\u003eDebounced value: {value}\u003c/p\u003e\n      \u003cbutton onClick={debounced.cancel}\u003eCancel Debounce cycle\u003c/button\u003e\n    \u003c/div\u003e\n  );\n}\n\nconst rootElement = document.getElementById('root');\nReactDOM.render(\u003cInput defaultValue=\"Hello world\" /\u003e, rootElement);\n```\n\nThe same API is available for `useDebounce` calls:\n```js\nconst [value, {cancel, isPending, flush}] = useDebounce(valueToDebounce);\n...\ncancel() // cancels pending debounce request\nisPending() // returns if there is a pending debouncing request\nflush() // immediately flushes pending request\n```\n\n\n#### Flush method\n\n`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.\n\n```javascript\nimport React, { useState } from 'react';\nimport { useDebouncedCallback } from 'use-debounce';\n\nfunction InputWhichFetchesSomeData({ defaultValue, asyncFetchData }) {\n  const debounced = useDebouncedCallback(\n    (value) =\u003e {\n      asyncFetchData;\n    },\n    500,\n    { maxWait: 2000 }\n  );\n\n  // When the component goes to be unmounted, we will fetch data if the input has changed.\n  useEffect(\n    () =\u003e () =\u003e {\n      debounced.flush();\n    },\n    [debounced]\n  );\n\n  return (\n    \u003cinput\n      defaultValue={defaultValue}\n      onChange={(e) =\u003e debounced(e.target.value)}\n    /\u003e\n  );\n}\n```\n\n#### isPending method\n\n`isPending` method shows whether component has pending callbacks. Works for both `useDebounce` and `useDebouncedCallback`:\n\n```javascript\nimport React, { useCallback } from 'react';\n\nfunction Component({ text }) {\n  const debounced = useDebouncedCallback(\n    useCallback(() =\u003e {}, []),\n    500\n  );\n\n  expect(debounced.isPending()).toBeFalsy();\n  debounced();\n  expect(debounced.isPending()).toBeTruthy();\n  debounced.flush();\n  expect(debounced.isPending()).toBeFalsy();\n\n  return \u003cspan\u003e{text}\u003c/span\u003e;\n}\n```\n\n#### leading/trailing calls\n\nBoth `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.\n\nFor more information on how leading debounce calls work see: https://lodash.com/docs/#debounce\n\n```javascript\nimport React, { useState } from 'react';\nimport { useDebounce } from 'use-debounce';\n\nexport default function Input() {\n  const [text, setText] = useState('Hello');\n  const [value] = useDebounce(text, 1000, { leading: true });\n\n  // value is updated immediately when text changes the first time,\n  // but all subsequent changes are debounced.\n  return (\n    \u003cdiv\u003e\n      \u003cinput\n        defaultValue={'Hello'}\n        onChange={(e) =\u003e {\n          setText(e.target.value);\n        }}\n      /\u003e\n      \u003cp\u003eActual value: {text}\u003c/p\u003e\n      \u003cp\u003eDebounce value: {value}\u003c/p\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n#### Options:\n\nYou can provide additional options as a third argument to both `useDebounce` and `useDebouncedCallback`:\n\n| option     | default                       | Description                                                                                                                      | Example                                                                |\n| ---------- | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |\n| 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 |\n| 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                  |\n| trailing   | true                          | This param executes the function after timeout.                                                                                  | https://github.com/xnimorz/use-debounce#leading-calls                  |\n| equalityFn | (prev, next) =\u003e prev === next | [useDebounce ONLY] Comparator function which shows if timeout should be started                                                  |                                                                        |\n\n## useThrottledCallback\n\nYou are able to use throttled callback with this library also (starting 5.2.0 version).\nFor this purpose use:\n\n```\nimport useThrottledCallback from 'use-debounce/useThrottledCallback';\n```\n\nor\n\n```\nimport { useThrottledCallback } from 'use-debounce';\n```\n\nSeveral examples:\n\n1. Avoid excessively updating the position while scrolling.\n\n   ```js\n   const scrollHandler = useThrottledCallback(updatePosition, 100);\n   window.addEventListener('scroll', scrollHandler);\n   ```\n\n2. Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.\n   ```js\n   const throttled = useThrottledCallback(renewToken, 300000, { 'trailing': false })\n   \u003cbutton onClick={throttled}\u003eclick\u003c/button\u003e\n   ```\n\nAll the params for `useThrottledCallback` are the same as for `useDebouncedCallback` except `maxWait` option. As it's not needed for throttle callbacks.\n\n# Special thanks:\n\n[@tryggvigy](https://github.com/tryggvigy) — for managing lots of new features of the library like trailing and leading params, throttle callback, etc;\n\n[@omgovich](https://github.com/omgovich) — for reducing bundle size.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxnimorz%2Fuse-debounce","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxnimorz%2Fuse-debounce","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxnimorz%2Fuse-debounce/lists"}