KyleHQ

Honest, loyal, senior software engineer, looking to make a real difference by putting people first.

KyleHQ © 2024
Svelte Gotcha - The Reactive Microtasks

Svelte Gotcha - The Reactive Microtasks

August 30, 2021
|
code
|
feedarmy
|
sveltejs

One of the USP’s of Svelte is of course its “reactivity”. As their homepage proudly declares

No more complex state management libraries — Svelte brings reactivity to JavaScript itself

And on any given day, developing with Svelte and its reactive nature is simply a dream to use. You can tell Svelte to track state changes on practically anything using the $: directive. And it’s quite likely that your first reactive changes will produce all the expected UI results. But as you start to rely more on UI updates based on variable or array/object changes, it’s likely that your UI will start skipping a beat and dropping values that you know explicitly to be there.

Due to the constant stream of updated feed data that Feed Army handles, I too encountered this issue. As my feeds would update, the UI would attempt to reactively iterate over each of the new feed entries for the user display. Yet feed entries were dropped on UI updates and I didn’t understand why?

To help, lets review this simple/common example that perfectly illustrates the issue. I suggest you view the REPL: svelte.dev/repl/567089d42c3b4146820e51ebb38b6f59, Click the " + " button and view the output of the console tab. You can also experiment more by removing the await tick(); call to see the console output 4x “1”

Here, the source code to clarify:

<script>
import { tick } from "svelte";

let element; let number = 1;   async function onClick() {   number++;   console.log(element.textContent); // will be 1   number = 2;   console.log(element.textContent); // will be 1   number = 3;   console.log(element.textContent); // will be 1   await tick(); // Remove this all to see 1 4x times   console.log(element.textContent); // will be 3, the last change on the number variable } </script> <div bind:this={element}>{number}</div> <button on:click={onClick}> + </button>

So what’s going on here, why will the console output 1 when number is bound with 2 & 3? And wisely, why has the author added the await tick();? This is best answered by the official docs: svelte.dev/tutorial/tick

When you update component state in Svelte, it doesn’t update the DOM immediately. Instead, it waits until the next microtask to see if there are any other changes that need to be applied, including in other components.

And of course this makes total sense so that optimisations can be made to stop burning cpu cycles and to allow for the batching of UI updates. Once you know why the UI is not being updated as you think it should, you can then take steps to handle this behaviour. In my case, I made use of a boolean flag to inform application code that updates were available. Processing was then completed by using a Queue based off a custom Svelte store. In this way, UI code was reactively aware of updates, and could process every new feed entry via a queue to ensure that no entries were missed.

If you are interested more in Sveltes' reactive stores (you should be as they are brilliant), I made another featured post about my reactive Queue Store here.

I hope that in clarifying on how you are bound to Sveltes' “Microtasks”, that you can design you code to maximise its behaviour.