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.
Debounced watchers pattern in 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.
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) })
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) })
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.
<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>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.
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.
Practice
Solution
Step 1: Understand what debounce means
Debounce means waiting until changes stop before reacting, avoiding too many reactions.Step 2: Apply debounce to Vue watchers
Debounced watchers delay the reaction to data changes until the user stops changing the data for a set time.Final Answer:
To delay the reaction to a data change until the changes stop for a short time -> Option BQuick Check:
Debounced watcher delays reaction = D [OK]
- Thinking watchers react immediately without delay
- Confusing debounce with throttling
- Believing debounce stops all reactions
Solution
Step 1: Identify common debounce sources
Lodash-es is a popular library providing debounce functions for JavaScript.Step 2: Check Vue imports
Vue itself does not export debounce; it must be imported from utility libraries like lodash-es.Final Answer:
import { debounce } from 'lodash-es'; -> Option CQuick Check:
Debounce from lodash-es = A [OK]
- Trying to import debounce directly from Vue
- Confusing debounce with Vue Router features
- Using incorrect package names
import { ref, watch } from 'vue';
import { debounce } from 'lodash-es';
const search = ref('');
watch(search, debounce((newVal) => {
console.log('Search:', newVal);
}, 300));Solution
Step 1: Understand debounce effect on watcher
The debounce delays the watcher callback until 300ms after the last change.Step 2: Predict console output
When typing quickly, the callback waits and logs only once after typing stops for 300ms.Final Answer:
Logs only once after the user stops typing for 300ms -> Option AQuick Check:
Debounced watcher logs once after delay = A [OK]
- Expecting logs on every keystroke
- Thinking debounce disables logging
- Confusing debounce delay with immediate calls
import { ref, watch } from 'vue';
import { debounce } from 'lodash-es';
const query = ref('');
watch(query, () => {
debounce(() => {
console.log('Query:', query.value);
}, 500)();
});Solution
Step 1: Analyze debounce usage inside watcher
Debounce is created inside the watcher callback, so a new debounced function is made on every change.Step 2: Understand debounce effect
This prevents debounce from working properly because the delay resets each time, causing no real debounce.Final Answer:
Debounce is called inside watcher callback, creating a new debounced function every time -> Option DQuick Check:
Debounce recreated each call = B [OK]
- Defining debounce inside watcher callback
- Forgetting to reuse the same debounced function
- Misunderstanding debounce lifecycle
import { ref, watch } from 'vue';
import { debounce } from 'lodash-es';
const searchTerm = ref('');
// What is the correct watcher setup?Solution
Step 1: Create debounce function once
Define debouncedFetch outside watcher to keep the same debounced function.Step 2: Use watcher to call debounced function
Watcher calls debouncedFetch with new value, so fetchResults runs after 400ms of no changes.Final Answer:
const debouncedFetch = debounce((val) => fetchResults(val), 400); watch(searchTerm, (val) => debouncedFetch(val)); -> Option AQuick Check:
Debounce created once, watcher calls it = C [OK]
- Calling debounce inside watcher callback directly
- Not passing the value to debounced function
- Calling debounced function immediately instead of passing reference
Ready to prove it?
Pass the test and this pattern moves unknown
