Docs
CodeRabbit
Cloudflare
AG Grid
SerpAPI
Netlify
OpenRouter
Neon
WorkOS
Clerk
Electric
PowerSync
Sentry
Railway
Prisma
Strapi
Unkey
CodeRabbit
Cloudflare
AG Grid
SerpAPI
Netlify
OpenRouter
Neon
WorkOS
Clerk
Electric
PowerSync
Sentry
Railway
Prisma
Strapi
Unkey
Debouncer API Reference
Throttler API Reference
Rate Limiter API Reference
Queue API Reference
Batcher API Reference

Vue Example: UseDebouncer

<script setup lang="ts">
import { TanStackDevtools } from '@tanstack/vue-devtools'
import { pacerDevtoolsPlugin } from '@tanstack/vue-pacer-devtools'
import { ref } from 'vue'
import { useDebouncer } from '@tanstack/vue-pacer/debouncer'

const dev = import.meta.env.DEV
const plugins = [pacerDevtoolsPlugin()]

const instantCount = ref(0)
const debouncedCount = ref(0)
const debouncer = useDebouncer(
  (count: number) => {
    debouncedCount.value = count
  },
  {
    key: 'counter',
    wait: 800,
    enabled: () => instantCount.value > 2,
    // leading: true, // optional, defaults to false
  },
  // Alternative to Subscribe: select state here to update this component.
  // (state) => state,
)

function increment() {
  debouncer.maybeExecute(++instantCount.value)
}

const searchText = ref('')
const debouncedSearchText = ref('')
const setSearchDebouncer = useDebouncer(
  (value: string) => {
    debouncedSearchText.value = value
  },
  { key: 'search', wait: 500, enabled: () => searchText.value.length > 2 },
)

function handleSearchChange(event: Event) {
  searchText.value = (event.target as HTMLInputElement).value
  setSearchDebouncer.maybeExecute(searchText.value)
}

const currentValue = ref(50)
const debouncedValue = ref(50)
const instantExecutionCount = ref(0)
const wait = ref(250)
const enabled = ref(true)
const setValueDebouncer = useDebouncer(
  (value: number) => {
    debouncedValue.value = value
  },
  () => ({ key: 'range', wait: wait.value, enabled: enabled.value }),
)

function handleRangeChange(event: Event) {
  currentValue.value = (event.target as HTMLInputElement).valueAsNumber
  instantExecutionCount.value++
  setValueDebouncer.maybeExecute(currentValue.value)
}
</script>

<template>
  <div>
    <div>
      <h1>TanStack Pacer useDebouncer Example 1</h1>
      <table>
        <tbody>
          <debouncer.Subscribe
            :selector="
              (state) => ({
                status: state.status,
                executionCount: state.executionCount,
              })
            "
            v-slot="{ status, executionCount }"
          >
            <tr>
              <td>Status:</td>
              <td>{{ status }}</td>
            </tr>
            <tr>
              <td>Execution Count:</td>
              <td>{{ executionCount }}</td>
            </tr>
          </debouncer.Subscribe>
          <tr>
            <td colspan="2"><hr /></td>
          </tr>
          <tr>
            <td>Instant Count:</td>
            <td>{{ instantCount }}</td>
          </tr>
          <tr>
            <td>Debounced Count:</td>
            <td>{{ debouncedCount }}</td>
          </tr>
        </tbody>
      </table>
      <div>
        <button @click="increment">Increment</button>
        <button @click="debouncer.flush()" style="margin-left: 10px">
          Flush
        </button>
      </div>
      <debouncer.Subscribe :selector="(state) => state" v-slot="state">
        <pre style="margin-top: 20px">{{ JSON.stringify(state, null, 2) }}</pre>
      </debouncer.Subscribe>
    </div>
    <hr />
    <div>
      <h1>TanStack Pacer useDebouncer Example 2</h1>
      <div>
        <input
          autofocus
          type="search"
          :value="searchText"
          @input="handleSearchChange"
          placeholder="Type to search..."
          style="width: 100%; margin-bottom: 1rem"
        />
      </div>
      <table>
        <tbody>
          <setSearchDebouncer.Subscribe
            :selector="
              (state) => ({
                isPending: state.isPending,
                executionCount: state.executionCount,
              })
            "
            v-slot="{ isPending, executionCount }"
          >
            <tr>
              <td>Is Pending:</td>
              <td>{{ isPending.toString() }}</td>
            </tr>
            <tr>
              <td>Execution Count:</td>
              <td>{{ executionCount }}</td>
            </tr>
          </setSearchDebouncer.Subscribe>
          <tr>
            <td colspan="2"><hr /></td>
          </tr>
          <tr>
            <td>Instant Search:</td>
            <td>{{ searchText }}</td>
          </tr>
          <tr>
            <td>Debounced Search:</td>
            <td>{{ debouncedSearchText }}</td>
          </tr>
        </tbody>
      </table>
      <div><button @click="setSearchDebouncer.flush()">Flush</button></div>
      <setSearchDebouncer.Subscribe :selector="(state) => state" v-slot="state">
        <pre style="margin-top: 20px">{{ JSON.stringify(state, null, 2) }}</pre>
      </setSearchDebouncer.Subscribe>
    </div>
    <hr />
    <div>
      <h1>TanStack Pacer useDebouncer Example 3</h1>
      <fieldset>
        <legend>Reactive options</legend>
        <label>
          Delay: {{ wait }} ms<input
            type="range"
            min="0"
            max="1500"
            step="50"
            v-model.number="wait"
          />
        </label>
        <label><input type="checkbox" v-model="enabled" />Enabled</label>
        <p>
          Changing the delay affects the next scheduled call. Disabling cancels
          pending work.
        </p>
      </fieldset>
      <div style="margin-bottom: 20px">
        <label
          >Current Range:<input
            type="range"
            min="0"
            max="100"
            :value="currentValue"
            @input="handleRangeChange"
            style="width: 100%"
          />
          <span>{{ currentValue }}</span>
        </label>
      </div>
      <div style="margin-bottom: 20px">
        <label
          >Debounced Range (Readonly):<input
            type="range"
            min="0"
            max="100"
            :value="debouncedValue"
            disabled
            style="width: 100%"
          />
          <span>{{ debouncedValue }}</span>
        </label>
      </div>
      <table>
        <tbody>
          <setValueDebouncer.Subscribe
            :selector="
              (state) => ({
                isPending: state.isPending,
                executionCount: state.executionCount,
              })
            "
            v-slot="{ isPending, executionCount }"
          >
            <tr>
              <td>Is Pending:</td>
              <td>{{ isPending.toString() }}</td>
            </tr>
            <tr>
              <td>Instant Executions:</td>
              <td>{{ instantExecutionCount }}</td>
            </tr>
            <tr>
              <td>Debounced Executions:</td>
              <td>{{ executionCount }}</td>
            </tr>
            <tr>
              <td>Saved Executions:</td>
              <td>{{ instantExecutionCount - executionCount }}</td>
            </tr>
            <tr>
              <td>% Reduction:</td>
              <td>
                {{
                  instantExecutionCount === 0
                    ? '0'
                    : Math.round(
                        ((instantExecutionCount - executionCount) /
                          instantExecutionCount) *
                          100,
                      )
                }}%
              </td>
            </tr>
          </setValueDebouncer.Subscribe>
        </tbody>
      </table>
      <div style="color: #666; font-size: 0.9em">
        <p>Debounced to {{ wait }}ms wait time</p>
      </div>
      <div><button @click="setValueDebouncer.flush()">Flush</button></div>
      <setValueDebouncer.Subscribe :selector="(state) => state" v-slot="state">
        <pre style="margin-top: 20px">{{ JSON.stringify(state, null, 2) }}</pre>
      </setValueDebouncer.Subscribe>
    </div>
  </div>

  <TanStackDevtools v-if="dev" :plugins="plugins" />
</template>
<script setup lang="ts">
import { TanStackDevtools } from '@tanstack/vue-devtools'
import { pacerDevtoolsPlugin } from '@tanstack/vue-pacer-devtools'
import { ref } from 'vue'
import { useDebouncer } from '@tanstack/vue-pacer/debouncer'

const dev = import.meta.env.DEV
const plugins = [pacerDevtoolsPlugin()]

const instantCount = ref(0)
const debouncedCount = ref(0)
const debouncer = useDebouncer(
  (count: number) => {
    debouncedCount.value = count
  },
  {
    key: 'counter',
    wait: 800,
    enabled: () => instantCount.value > 2,
    // leading: true, // optional, defaults to false
  },
  // Alternative to Subscribe: select state here to update this component.
  // (state) => state,
)

function increment() {
  debouncer.maybeExecute(++instantCount.value)
}

const searchText = ref('')
const debouncedSearchText = ref('')
const setSearchDebouncer = useDebouncer(
  (value: string) => {
    debouncedSearchText.value = value
  },
  { key: 'search', wait: 500, enabled: () => searchText.value.length > 2 },
)

function handleSearchChange(event: Event) {
  searchText.value = (event.target as HTMLInputElement).value
  setSearchDebouncer.maybeExecute(searchText.value)
}

const currentValue = ref(50)
const debouncedValue = ref(50)
const instantExecutionCount = ref(0)
const wait = ref(250)
const enabled = ref(true)
const setValueDebouncer = useDebouncer(
  (value: number) => {
    debouncedValue.value = value
  },
  () => ({ key: 'range', wait: wait.value, enabled: enabled.value }),
)

function handleRangeChange(event: Event) {
  currentValue.value = (event.target as HTMLInputElement).valueAsNumber
  instantExecutionCount.value++
  setValueDebouncer.maybeExecute(currentValue.value)
}
</script>

<template>
  <div>
    <div>
      <h1>TanStack Pacer useDebouncer Example 1</h1>
      <table>
        <tbody>
          <debouncer.Subscribe
            :selector="
              (state) => ({
                status: state.status,
                executionCount: state.executionCount,
              })
            "
            v-slot="{ status, executionCount }"
          >
            <tr>
              <td>Status:</td>
              <td>{{ status }}</td>
            </tr>
            <tr>
              <td>Execution Count:</td>
              <td>{{ executionCount }}</td>
            </tr>
          </debouncer.Subscribe>
          <tr>
            <td colspan="2"><hr /></td>
          </tr>
          <tr>
            <td>Instant Count:</td>
            <td>{{ instantCount }}</td>
          </tr>
          <tr>
            <td>Debounced Count:</td>
            <td>{{ debouncedCount }}</td>
          </tr>
        </tbody>
      </table>
      <div>
        <button @click="increment">Increment</button>
        <button @click="debouncer.flush()" style="margin-left: 10px">
          Flush
        </button>
      </div>
      <debouncer.Subscribe :selector="(state) => state" v-slot="state">
        <pre style="margin-top: 20px">{{ JSON.stringify(state, null, 2) }}</pre>
      </debouncer.Subscribe>
    </div>
    <hr />
    <div>
      <h1>TanStack Pacer useDebouncer Example 2</h1>
      <div>
        <input
          autofocus
          type="search"
          :value="searchText"
          @input="handleSearchChange"
          placeholder="Type to search..."
          style="width: 100%; margin-bottom: 1rem"
        />
      </div>
      <table>
        <tbody>
          <setSearchDebouncer.Subscribe
            :selector="
              (state) => ({
                isPending: state.isPending,
                executionCount: state.executionCount,
              })
            "
            v-slot="{ isPending, executionCount }"
          >
            <tr>
              <td>Is Pending:</td>
              <td>{{ isPending.toString() }}</td>
            </tr>
            <tr>
              <td>Execution Count:</td>
              <td>{{ executionCount }}</td>
            </tr>
          </setSearchDebouncer.Subscribe>
          <tr>
            <td colspan="2"><hr /></td>
          </tr>
          <tr>
            <td>Instant Search:</td>
            <td>{{ searchText }}</td>
          </tr>
          <tr>
            <td>Debounced Search:</td>
            <td>{{ debouncedSearchText }}</td>
          </tr>
        </tbody>
      </table>
      <div><button @click="setSearchDebouncer.flush()">Flush</button></div>
      <setSearchDebouncer.Subscribe :selector="(state) => state" v-slot="state">
        <pre style="margin-top: 20px">{{ JSON.stringify(state, null, 2) }}</pre>
      </setSearchDebouncer.Subscribe>
    </div>
    <hr />
    <div>
      <h1>TanStack Pacer useDebouncer Example 3</h1>
      <fieldset>
        <legend>Reactive options</legend>
        <label>
          Delay: {{ wait }} ms<input
            type="range"
            min="0"
            max="1500"
            step="50"
            v-model.number="wait"
          />
        </label>
        <label><input type="checkbox" v-model="enabled" />Enabled</label>
        <p>
          Changing the delay affects the next scheduled call. Disabling cancels
          pending work.
        </p>
      </fieldset>
      <div style="margin-bottom: 20px">
        <label
          >Current Range:<input
            type="range"
            min="0"
            max="100"
            :value="currentValue"
            @input="handleRangeChange"
            style="width: 100%"
          />
          <span>{{ currentValue }}</span>
        </label>
      </div>
      <div style="margin-bottom: 20px">
        <label
          >Debounced Range (Readonly):<input
            type="range"
            min="0"
            max="100"
            :value="debouncedValue"
            disabled
            style="width: 100%"
          />
          <span>{{ debouncedValue }}</span>
        </label>
      </div>
      <table>
        <tbody>
          <setValueDebouncer.Subscribe
            :selector="
              (state) => ({
                isPending: state.isPending,
                executionCount: state.executionCount,
              })
            "
            v-slot="{ isPending, executionCount }"
          >
            <tr>
              <td>Is Pending:</td>
              <td>{{ isPending.toString() }}</td>
            </tr>
            <tr>
              <td>Instant Executions:</td>
              <td>{{ instantExecutionCount }}</td>
            </tr>
            <tr>
              <td>Debounced Executions:</td>
              <td>{{ executionCount }}</td>
            </tr>
            <tr>
              <td>Saved Executions:</td>
              <td>{{ instantExecutionCount - executionCount }}</td>
            </tr>
            <tr>
              <td>% Reduction:</td>
              <td>
                {{
                  instantExecutionCount === 0
                    ? '0'
                    : Math.round(
                        ((instantExecutionCount - executionCount) /
                          instantExecutionCount) *
                          100,
                      )
                }}%
              </td>
            </tr>
          </setValueDebouncer.Subscribe>
        </tbody>
      </table>
      <div style="color: #666; font-size: 0.9em">
        <p>Debounced to {{ wait }}ms wait time</p>
      </div>
      <div><button @click="setValueDebouncer.flush()">Flush</button></div>
      <setValueDebouncer.Subscribe :selector="(state) => state" v-slot="state">
        <pre style="margin-top: 20px">{{ JSON.stringify(state, null, 2) }}</pre>
      </setValueDebouncer.Subscribe>
    </div>
  </div>

  <TanStackDevtools v-if="dev" :plugins="plugins" />
</template>