0
0
Vueframework~5 mins

Debounced watchers pattern in Vue

Choose your learning style9 modes available
Introduction

Debounced watchers help delay reacting to changes until the user stops making changes for a moment. This avoids doing work too often and improves performance.

When watching a search input to avoid sending a request on every keystroke.
When tracking window resize events but want to update layout only after resizing stops.
When validating form fields but want to wait until the user pauses typing.
When syncing data to a server but want to reduce the number of updates.
Syntax
Vue
import { ref, watch } from 'vue'
import { debounce } from 'lodash-es' // or your debounce utility

const state = ref('')

const debouncedWatcher = debounce((newValue) => {
  // react to newValue here
}, 300)

watch(state, (newValue) => {
  debouncedWatcher(newValue)
})

Use a debounce function from a utility library or write your own.

Debounce delay is in milliseconds and controls how long to wait after the last change.

Examples
This example waits 500ms after the user stops typing before logging the search term.
Vue
import { ref, watch } from 'vue'
import { debounce } from 'lodash-es'

const searchTerm = ref('')

const debouncedSearch = debounce((term) => {
  console.log('Searching for:', term)
}, 500)

watch(searchTerm, (newTerm) => {
  debouncedSearch(newTerm)
})
This example shows a simple custom debounce function without external libraries.
Vue
import { ref, watch } from 'vue'

function debounce(fn, delay) {
  let timer
  return function(...args) {
    clearTimeout(timer)
    timer = setTimeout(() => fn(...args), delay)
  }
}

const input = ref('')

const debouncedLog = debounce((val) => {
  console.log('Input changed to:', val)
}, 300)

watch(input, (val) => {
  debouncedLog(val)
})
Sample Program

This Vue 3 component uses a debounced watcher to update the displayed value only after the user stops typing for 400ms. It improves performance by not updating on every keystroke.

Vue
<template>
  <div>
    <label for="search">Search:</label>
    <input id="search" v-model="searchTerm" type="text" aria-label="Search input" />
    <p>Debounced value: {{ debouncedValue }}</p>
  </div>
</template>

<script setup>
import { ref, watch } from 'vue'

function debounce(fn, delay) {
  let timer
  return function(...args) {
    clearTimeout(timer)
    timer = setTimeout(() => fn(...args), delay)
  }
}

const searchTerm = ref('')
const debouncedValue = ref('')

const updateDebouncedValue = debounce((val) => {
  debouncedValue.value = val
}, 400)

watch(searchTerm, (val) => {
  updateDebouncedValue(val)
})
</script>

<style scoped>
input {
  padding: 0.5rem;
  font-size: 1rem;
  border: 1px solid #ccc;
  border-radius: 0.25rem;
  width: 100%;
  max-width: 300px;
}
p {
  margin-top: 0.5rem;
  font-weight: 600;
}
</style>
OutputSuccess
Important Notes

Debounced watchers help reduce unnecessary work and improve user experience.

Always clear timers properly to avoid memory leaks.

Use aria-label on inputs for accessibility.

Summary

Debounced watchers delay reactions until changes stop for a set time.

They are useful for inputs, resizing, and other frequent events.

Use debounce functions with Vue's watch to implement this pattern.