(Hey, we're having problems showing images in RSS right now, so if you want a better reading experience, consider viewing this article online [here](https://zellwk.com//blog/svelte-reactive-bindings-speed. We hope to fix this soon!).
Svelte's reactive bindings execute slower than keydown
, keypress
, and input
events, but faster than keyup
events.
The order is as follows:
keydown
keypress
input
- Svelte's reactive bindings update here
keyup
You probably won't need keyboard event listeners if you're using Svelte's bindings because the bindings are usually sufficient:
<script>
let value = ''
$: {
// Do something with value
}
</script>
<input bind:value />
But if you ever need them, there are a couple of ways to handle their difference.
- Defer execution
- Use keyup instead
- Don't bind
Defer execution
The first method is to defer execution of the event handler — so event.target.value
will use the same value from the Svelte binding.
The simplest way is with setTimeout
:
<script>
let value = ''
function handleInput(event) {
setTimeout(_ => {
// Use value here
}, 0)
}
</script>
<input bind:value on:input={handleInput} />
An alternative way is to use setTimeout
's promise-variant to defer execution.
<script>
let value = ''
async function handleInput(event) {
await delay()
// Use value here
}
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
</script>
<input bind:value on:input={handleInput} />
But you cannot use Svelte's built-in tick
function. This triggers too quickly for some reason, so the binding would not be updated in the event listener.
<script>
import { tick } from 'svelte'
let value = ''
async function handleInput(event) {
await tick()
// value would not be updated yet
}
</script>
<input bind:value on:input={handleInput} />
Of course, debouncing works. This may be the ideal solution if you need to handle asynchronous tasks.
<script>
let value = ''
async function handleInput(event) {
// Use value here
}
</script>
<input bind:value on:input={debounce(handleInput, 200)} />
Use keyup
If you wish to skip the binding trouble, you can use keyup
instead of other keyboard events. This assumes keyup
works for what you're trying to do.
<script>
let value = ''
async function handleKeyup(event) {
// Use value here
}
</script>
<input bind:value on:keyup={handleKeyup} />
Don't bind
The third (perhaps most preferred) way is simply not to bind. To do this, we just set the initial value
and adjust it whenever we need to.
<script>
let value = ''
async function handleInput(event) {
value = event.target.value
}
</script>
<input {value} on:input={handleInput} />
Wrapping up
That's everything you need to know about the relationship between Svelte's reactive bindings and event listeners.
This might change in Svelte 5, though I think it's unlikely. I'll update this article or write a new one when I play around with Svelte 5.
Have fun in the meantime!