Search code examples
vuejs3debouncingnuxt3.js

Debounce vue3 + nuxt3 js


I have some question. I want debounce an emit event from child component to parent component ( using el-input in element plus).

I try learn some solutions but emit debounce not working such as watch input, emit modelValue. I want to pass 1 "debounce" parameter as above and prevent the code from working fine.

//Custom Input
<script lang="ts" setup>
const search = ref('')
</script>

<template>
  <CustomInput
    :model-value="search"
    placeholder="Search"
    type="search"
    class="w-full md:max-w-[330px]"
    :debounce="500"
    @update:modelValue="(newValue: string) => (search = newValue)"
  />
</template>
//input
<script lang="ts" setup>
interface Props {
  modelValue?: string
  placeholder?: string
  type: string
  debounce: number
}
const props = withDefaults(defineProps<Props>(), {
  modelValue: '',
  placeholder: 'Please input',
  type: 'text',
  debounce: 0
})
const emit = defineEmits(['update:modelValue'])
// const debounceInput = debounce(() => {
//   let value = 'ok'
//   emit('update:modelValue', value)
// }, props.debounce)
const debounceInput = (e: any) => {
  let value = e.target.value
  emit('update:modelValue', value)
}
</script>

<template>
  <el-input
    v-bind="$attrs"
    :value="modelValue"
    :placeholder="placeholder"
    :type="type"
    class="base-input"
    :class="{
      search: type === 'search'
    }"
    @input="debounceInput"
  >
    <template #suffix>
      <el-icon>
        <img
          v-if="type === 'search'"
          class="w-[18px] h-[18px] mx-auto cursor-pointer"
          src="images/search.svg"
          alt="logo"
        />
      </el-icon>
    </template>
  </el-input>
</template>
//debounce function
export const debounce = (callback: Function, delayTime: number) => {
  let timeOut
  return () => {
    timeOut = setTimeout(() => callback(), delayTime)
  }
}


Solution

  • debouncing a function:

    export function debounce(func, timeout) {
      let timeoutId;
      return (...args) => {
        clearTimeout(timeoutId);
        timeoutId = setTimeout(() => {
          func(...args);
        }, timeout);
      };
    }
    

    Then to use it:

    <script>
    import { debounce } from 'debounce.js'
    
    const debouncedInput = debounce((e) => 
      emit("update:modelValue", e.target.value),
      300 // timeout in ms
    );
    </script>
    

    with a generic <input> for simplicity sake:

    <template>
      <input
        :value="modelValue"
        @input="debouncedInput"
        placeholder="Please input"
        type="text"
      />
    </template>
    

    Here is a codesandbox example. Should also work just fine when implemented with <el-input> and typescript which I'll leave to you.

    By the way, these properties you have on <CustomInput>:

    :modelValue="search"
    @update:modelValue="(newValue: string) => (search = newValue)"
    

    Can all be replaced with the following short-hand:

    v-model="search"