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.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs