Debounce inside a Vue composable

by

in

In the Queerlit frontend, I keep a query object in vuex state, and there’s a helper function for modifying the query object and then immediately performing a search request. This helper lives in a composable, useSearch() in search.composable.js.

The search function is debounced, because it may be issued multiple times, quickly in succession. This happens for instance when using autocomplete. When selecting a suggested term:

  1. Clear the free-text input (update query and search!)
  2. Add the selected term object (update query and search!)

However, the debounced function is created (debounce invoked) inside the composable. When using the composable from different components/composables, they will each generate and use its own debounced function, and the debouncing has no effect. It will do the delay part, there is of course no way for one function to abort earlier invocations of another function.

To make sure that different composable users will use the same object, I had to move the object up to module scope. I couldn’t actually do the debouncing there, though, because the search function depends on other composables. Best practice seems to be to not use composables outside the setup function or other composables.

So this is the structure of my solution:

let debouncedSearch;

export default function useSearch() {
  const { commit } = useStore(); // This is used in doSearch()
  
  async function doSearch() {
    // await an API request
    // commit results to store
  }

  debouncedSearch = debounce(doSearch, 50);
 
  function setQuery(params) {
    // commit query modifications to store
    debouncedSearch();
  }
}

The debounced function is declared outside the composable, in module scope. But it is defined (given its value) inside the composable.

Each usage of the composable will redefine the function (invoke debounce) but then it will update the module-scope variable, so that all users will, in the end, use the same debounced function.

Does this help you? Do you know of another (better) way to use debounce inside a composable?


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *