---
title: Cookbook | Debouncer
contributors:
  - n8sabes
  - KenAKAFrosty
  - shairez
updated_at: '2024-03-07T01:00:00Z'
created_at: '2024-02-07T01:00:00Z'
---

import CodeSandbox, { CodeFile } from '../../../../components/code-sandbox/index.tsx';

# What is a debouncer and why it's important

A debouncer is a programming pattern used to ensure that time-consuming tasks do not fire too frequently, thereby preventing performance issues or the overwhelming of servers with requests. This is particularly useful in scenarios such as search inputs where you may not want to trigger a search request with every keystroke, but rather after the user has paused typing. 

By implementing a debouncer, you can enhance both user experience and application efficiency. This is achieved by delaying a function's execution until a specified amount of time has elapsed since its last invocation.


## When to use debouncers

Debouncers are best used in situations where you want to limit the frequency of function calls. Common use cases include:

- User input validation: Delaying validation until the user stops typing to avoid unnecessary processing for every keystroke.
- Search functionality: Waiting until a user finishes typing a search query to begin the search process, reducing the number of search requests sent to the server.
- Window resizing: Limiting the number of recalculations or adjustments when the browser window is resized.

## How to implement a debouncer in Qwik

The Qwik framework provides unique capabilities for managing state and effects in a way that is both serializable and efficient. Implementing a debouncer in Qwik involves using Qwik's primitives, such as `useSignal` for state management and `$` for marking functions that can capture state without breaking serialization. Below is a simple debouncer pattern. It behaves similarly to closure-based debouncers that execute a function when the timeout is reached.

<CodeFile src="/src/routes/demo/cookbook/mediaController/index.tsx">
```tsx
export const useDebouncer = <A extends readonly unknown[], R>(
  fn: QRL<(...args: A) => R>,
  delay: number,
): QRL<(...args: A) => void> => {
  const timeoutId = useSignal<number>();

  return $((...args: A): void => {
    window.clearTimeout(timeoutId.value);
    timeoutId.value = window.setTimeout((): void => {
      void fn(...args);
    }, delay);
  });
};
```
</CodeFile>

This debouncer takes a function and a delay as arguments. It utilizes `useSignal` to track the `timeoutID`, ensuring compatibility with Qwik's resumability model and its use of [QRL's](https://qwik.dev/docs/advanced/qrl/). The returned function, when called, clears any existing timeout and sets a new one to invoke the provided function after the specified delay.

## How to use the debouncer

The example below demonstrates using the debouncer in a component to efficiently manage user input. By debouncing the input, the application updates the state only after the user has stopped typing for 1-second, optimizing performance for operations such as API calls or data filtering.

<CodeFile src="/src/routes/demo/cookbook/mediaController/index.tsx">
```tsx
import { $, useSignal, component$, type QRL } from "@builder.io/qwik";
import { useDebouncer } from "~/utils/debouncer";

export default component$(() => {
  const debouncedValue = useSignal("");

  const debounce = useDebouncer(
    $((value: string) => {
      debouncedValue.value = value;
    }),
    1000
  );

  return (
    <>
      <input
        onInput$={(_, target) => {
          debounce(target.value);
        }}
      />
      <p>{debouncedValue.value}</p>
    </>
  );
});
```
</CodeFile>

## Live Demo

In the live demo below, `useDebouncer` is used to update the `debouncedValue` signal after a 1-second delay has elapsed since the last keystroke.

<CodeSandbox src="/src/routes/demo/cookbook/debouncer/"  style={{ height: '250px' }}>
</CodeSandbox>

## Bonus: `useDebouncer$`

To save our developers the extra "wrapping with a $()" action.

We can leverage Qwik's `implicit$FirstArg` function to create a `useDebouncer$` function that automatically wraps the provided function with `$()`.

This is how Qwik actually implements all of its built-in $ hooks.

```tsx
export const useDebouncerQrl = <A extends readonly unknown[], R>(
  fn: QRL<(...args: A) => R>,
  delay: number,
): QRL<(...args: A) => void> => {
  const timeoutId = useSignal<number>();

  return $((...args: A): void => {
    window.clearTimeout(timeoutId.value);
    timeoutId.value = window.setTimeout((): void => {
      void fn(...args);
    }, delay);
  });
};

export const useDebouncer$ = implicit$FirstArg(useDebouncerQrl);
```

And now we could do:

```tsx
const debounce = useDebouncer$(
  (value: string) => {
    debouncedValue.value = value;
  },
  1000
);
```

Pretty great, huh? :)


