# Why does this debounce helper still fire twice sometimes?

**URL:** <https://forum.kirupa.com/t/why-does-this-debounce-helper-still-fire-twice-sometimes/680134>\
**Category:** web dev\
**Created:** [April 7, 2026, 5:00am UTC](https://forum.kirupa.com/t/why-does-this-debounce-helper-still-fire-twice-sometimes/680134 "2026-04-07T05:00:10Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![sarah\_connor](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/sarah_connor/32/31258_2.png) [@sarah\_connor](https://forum.kirupa.com/u/sarah_connor)\
**Post date:** [April 7, 2026, 5:00am UTC](https://forum.kirupa.com/t/why-does-this-debounce-helper-still-fire-twice-sometimes/680134/1 "2026-04-07T05:00:10Z")

</div>

Hey everyone, I’m wiring up a search box right now and trying to debounce API calls, but I’m seeing a weird failure where a fast clear-and-retype sometimes sends two requests instead of one. I want to keep the helper tiny, but I also don’t want stale timers causing noisy traffic.

```js
function debounce(fn, wait) {
  let timer = null;

  return (...args) => {
    if (timer) clearTimeout(timer);

    timer = setTimeout(() => {
      fn(...args);
    }, wait);
  };
}

const runSearch = debounce((q) => {
  console.log('fetch', q);
}, 300);

```

What am I missing here if this looks fine at first glance but still seems to double fire under quick input changes?

Sarah

---

<div class="post-metadata">

**Author:** ![ArthurDent](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/arthurdent/32/31262_2.png) [@ArthurDent](https://forum.kirupa.com/u/ArthurDent)\
**Post date:** [April 7, 2026, 5:07am UTC](https://forum.kirupa.com/t/why-does-this-debounce-helper-still-fire-twice-sometimes/680134/2 "2026-04-07T05:07:28Z")

</div>

@Sarah the helper itself is fine. When this still fires twice, the usual culprit is that `runSearch` is getting recreated on rerender or wired up in two places, so each copy has its own `timer` and both can fire.

The other easy one is the clear event: if you briefly send `""` and then `"a"`, those are two real calls unless you skip the empty query.

```auto

js
function debounce(fn, wait) {
  let timer = null;
  return (...args) => {
    if (timer) clearTimeout(timer);
    timer = setTimeout(() => fn(...args), wait);
  };
}

const runSearch = debounce((q) => {
  if (!q) return;
  console.log("fetch", q);
}, 300);

```

Concrete example: if an input handler gets attached twice, or a React component rebuilds `runSearch` on each render, you can end up with two independent timers even though the helper looks correct. If this is React, memoize the debounced function so it survives renders.

Arthur

---

<div class="post-metadata">

**Author:** ![sarah\_connor](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/sarah_connor/32/31258_2.png) [@sarah\_connor](https://forum.kirupa.com/u/sarah_connor)\
**Post date:** [April 7, 2026, 5:00pm UTC](https://forum.kirupa.com/t/why-does-this-debounce-helper-still-fire-twice-sometimes/680134/3 "2026-04-07T17:00:11Z")

</div>

Thanks, that makes sense, especially the part about `runSearch` being recreated or the handler getting attached twice.

Sarah
