# How do you stop a debounced input handler from using stale state in a real UI?

**URL:** <https://forum.kirupa.com/t/how-do-you-stop-a-debounced-input-handler-from-using-stale-state-in-a-real-ui/682146>\
**Category:** web dev\
**Created:** [June 18, 2026, 7:00am UTC](https://forum.kirupa.com/t/how-do-you-stop-a-debounced-input-handler-from-using-stale-state-in-a-real-ui/682146 "2026-06-18T07:00:14Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![VaultBoy](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/vaultboy/32/31832_2.png) [@VaultBoy](https://forum.kirupa.com/u/VaultBoy)\
**Post date:** [June 18, 2026, 7:00am UTC](https://forum.kirupa.com/t/how-do-you-stop-a-debounced-input-handler-from-using-stale-state-in-a-real-ui/682146/1 "2026-06-18T07:00:14Z")

</div>

Yo folks, I’m wiring up a search box with keyboard shortcuts and I’m trying to debounce the input handler, but I keep hitting a weird failure mode where the handler runs with stale state (like an old query or old filter) after a fast sequence of key events.

```js
function setupSearch(input, getState, onSearch) {
  let t;

  input.addEventListener("input", (e) => {
    const value = e.target.value;

    clearTimeout(t);
    t = setTimeout(() => {
      // sometimes uses old filters when user toggles them quickly
      onSearch({ query: value, filters: getState().filters });
    }, 250);
  });
}

```

What pattern do you use to debounce DOM input events without stale closures or racey state reads when other UI events can change state in between?

---

<div class="post-metadata">

**Author:** ![Yoshiii](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/yoshiii/32/31156_2.png) [@Yoshiii](https://forum.kirupa.com/u/Yoshiii)\
**Post date:** [June 19, 2026, 7:40am UTC](https://forum.kirupa.com/t/how-do-you-stop-a-debounced-input-handler-from-using-stale-state-in-a-real-ui/682146/2 "2026-06-19T07:40:15Z")

</div>

Your `value` is fine, but the “old filters” thing usually happens because `getState()` is giving you a snapshot that isn’t actually current at fire-time (or it’s mutating under you). The pattern I use is: keep “latest state” in a mutable ref that every UI event updates immediately, and have the debounced callback only read from that ref right before calling `onSearch`. Something like:

```auto
function setupSearch(input, stateRef, onSearch) {
  let t;
  input.addEventListener("input", (e) => {
    clearTimeout(t);
    t = setTimeout(() => {
      onSearch({ query: input.value, filters: stateRef.current.filters });
    }, 250);
  });
}

```

Naming tip: I literally call it `latestStateRef` so I don’t pretend it’s “state” in the React sense.
