JAVASCRIPT
Implementing a Debounce Function with a Vue 3 Composable
Create a reusable `useDebounce` composable in Vue 3 to delay function execution, preventing excessive calls for user inputs like search fields or window resizing.
// composables/useDebounce.js
import { ref, onUnmounted } from 'vue';
export function useDebounce(fn, delay) {
const timeout = ref(null);
const debouncedFn = (...args) => {
if (timeout.value) {
clearTimeout(timeout.value);
}
timeout.value = setTimeout(() => {
fn(...args);
}, delay);
};
// Clear timeout on component unmount to prevent memory leaks
onUnmounted(() => {
if (timeout.value) {
clearTimeout(timeout.value);
}
});
return debouncedFn;
}
// App.vue (Example Usage)
<template>
<div class="container">
<h1>Debounce Composable Example</h1>
<p>Type something into the input below. The 'Search term' will only update after you stop typing for 500ms.</p>
<input
type="text"
v-model="inputValue"
@input="debouncedUpdateSearchTerm(inputValue)"
placeholder="Type here..."
/>
<p>Search term: <strong>{{ searchTerm }}</strong></p>
<p>Input value: <em>{{ inputValue }}</em></p>
<hr>
<h2>Button Debounce Example</h2>
<p>This button can only be clicked once every 1000ms.</p>
<button @click="debouncedProcessClick">Click Me (Debounced)</button>
<p v-if="clickMessage">{{ clickMessage }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue';
import { useDebounce } from './composables/useDebounce';
// --- Input Debounce Example ---
const inputValue = ref('');
const searchTerm = ref('');
// Function to update the search term, which we want to debounce
const updateSearchTerm = (value) => {
searchTerm.value = value;
console.log('Search term updated:', value);
};
// Create a debounced version of updateSearchTerm with a 500ms delay
const debouncedUpdateSearchTerm = useDebounce(updateSearchTerm, 500);
// --- Button Debounce Example ---
const clickMessage = ref('');
let clickCount = 0;
// Function to process a button click
const processClick = () => {
clickCount++;
clickMessage.value = `Button clicked: ${clickCount} times (last at ${new Date().toLocaleTimeString()})`;
console.log('Button clicked!', clickCount);
};
// Create a debounced version of processClick with a 1000ms delay
const debouncedProcessClick = useDebounce(processClick, 1000);
</script>
<style>
.container {
max-width: 700px;
margin: 50px auto;
padding: 25px;
border: 1px solid #eee;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.05);
font-family: Arial, sans-serif;
text-align: center;
}
input {
width: 80%;
padding: 10px;
margin-bottom: 20px;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 1em;
}
p strong {
color: #007bff;
}
p em {
color: #555;
}
button {
padding: 10px 20px;
background-color: #28a745;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 1em;
margin-top: 15px;
}
button:hover {
background-color: #218838;
}
hr {
margin: 40px 0;
border: 0;
border-top: 1px solid #eee;
}
</style>
How it works: This snippet introduces a `useDebounce` composable, a highly useful pattern for optimizing performance in Vue 3 applications. A debounce function ensures that a specific function is not called too frequently. Instead, it waits for a certain amount of inactivity (the 'delay') before executing the function. This is perfect for scenarios like real-time search inputs (to avoid making an API call on every keystroke), window resize events, or button clicks that should only register once within a period. The composable also handles cleanup on component unmount to prevent memory leaks.