How to debounce / throttle with Svelte?

11.5k views Asked by At

So i currently have:

App.html

<div>
  <input on:input="debounce(handleInput, 300)">
</div>

<script>
  import { debounce } from 'lodash'

  export default {
    data () {
      name: ''
    },

    methods: {
      debounce,
      async handleInput (event) {
        this.set({ name: await apiCall(event.target.value).response.name })
      }
    }
  }
</script>

And get the error Uncaught TypeError: Expected a function at App.debounce. This comes from Lodash so it doesn't seem like the method from Svelte is being passed through.

Extra extra edit

Extra context for how i'm currently achieving it:

oncreate () {
  const debounceFnc = this.handleInput.bind(this)

  this.refs.search.addEventListener('input', debounce(debounceFnc, 300))
}
2

There are 2 answers

4
Rich Harris On BEST ANSWER

It's the method itself that should be debounced — so rather than calling debounce on each input event, set handleInput up to be a debounced method:

Svelte v3 version

<input on:input={handleInput}>

<script>
  import debounce from 'lodash/debounce'

  let name = '';
    
  const handleInput = debounce(e => {
    name = e.target.value;
  }, 300)
</script>

REPL example here.

Older Svelte version

<div>
  <input on:input="handleInput(event)">
</div>

<script>
  import { debounce } from 'lodash'

  export default {
    data () {
      return { name: '' };
    },

    methods: {
      handleInput: debounce (async function (event) {
        this.set({ name: await apiCall(event.target.value).response.name })
      }, 300)
    }
  }
</script>

Simplified REPL example here.

1
Sven On

The accepted answer is valid for Svelte v1. For v3, you can achieve the same with this code:

<input placeholder='edit me' bind:this={input}>
<p>name: {name}</p>

<script>
  import { onMount } from "svelte"
    import { debounce } from 'lodash-es'
    var name="", input;
    onMount(()=>{
        input.addEventListener('input', debounce((e)=>{name=e.target.value}, 250))
    })
</script>